【C语言】多线程服务器

简介: 【C语言】多线程服务器

多线程服务器

步骤

主线程创建子线程,用子线程和客户端通信。
步骤:
1.使用socket函数,获取一个socket文件描述符
2.使用setsockopt端口复用
3.使用bind函数允许客户端的哪些ip可以访问服务器
4.使用listen监听客户端连接
5.使用accept从已连接的客户端队列中取出一个文件描述符,与它通信
6.使用pthread_create函数创建一个子线程去与上面的文件描述符通信
7.使用pthread_detach函数将子线程设置为分离属性,让它自动回收资源

代码

#include <socketwrap.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct info
{
   
    int cfd; // 若为-1表示可用, 大于0表示已被占用
    int idx;
    pthread_t thread;          // 由pthread_create 返回
    struct sockaddr_in client; // 由accept 返回
} INFO;

INFO thInfo[1024];

void initThreadArr()
{
   
    for (int i = 0; i < 1024; i++)
    {
   
        bzero(&thInfo[i],sizeof(thInfo[i]));
        thInfo[i].cfd = -1;
    }
}

int findIndex()
{
   
    int i;
    for (i = 0; i < 1024; i++)
    {
   
        if (thInfo[i].cfd == -1)
        {
   
            return i;
        }
    }
    if (i == 1024)
    {
   
        return -1;
    }
}

void *threadFunc(void *arg)
{
   
    INFO *curthread = (INFO *)arg;
    char sIP[16];
    printf("current thread id [%ld],arr index is [%d],cfd is [%d],client ip is [%s:%d]\n", pthread_self(), curthread->idx, curthread->cfd, inet_ntop(AF_INET, &curthread->client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(curthread->client.sin_port));
    char buff[64];
    while (1)
    {
   
        memset(buff, 0x00, sizeof(buff));
        int n = Read(curthread->cfd, buff, sizeof(buff));
        if (n == 0)
        {
   
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            return 0;
        }
        else if (n < 0)
        {
   
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            perror("child read error");
            return 0;
        }

        printf("child thread [%ld] recv data from [%s:%d]:[%s]\n", pthread_self(), inet_ntop(AF_INET, &curthread->client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(curthread->client.sin_port), buff);
        for (int i = 0; i < n; i++)
        {
   
            buff[i] = toupper(buff[i]);
        }
        n = Write(curthread->cfd, buff, n);
        if (n <= 0)
        {
   
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            perror("child write error");
            return 0;
        }
    }
}

int main()
{
   

    initThreadArr();

    int sfd = Socket(AF_INET, SOCK_STREAM, 0);

    // 设置端口复用
    int opt = 1;
    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));

    struct sockaddr_in soaddr;
    bzero(&soaddr, sizeof(soaddr));

    soaddr.sin_family = AF_INET;
    soaddr.sin_port = htons(9999);
    soaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    Bind(sfd, (struct sockaddr *)&soaddr, sizeof(soaddr));

    // 监听-listen
    Listen(sfd, 128);

    struct sockaddr_in clientsocket;
    socklen_t clilen;

    int cfd;
    int index;
    int ret;

    while (1)
    {
   
        index = -1;
        clilen = sizeof(clientsocket);
        bzero(&clientsocket, clilen);

        cfd = Accept(sfd, (struct sockaddr *)&clientsocket, &clilen);
        // 从线程数组中找一个可以用的
        index = findIndex();
        thInfo[index].idx = index;
        thInfo[index].client = clientsocket;
        thInfo[index].cfd = cfd;

        // 创建线程
        ret = pthread_create(&thInfo[index].thread, NULL, threadFunc, &thInfo[index]);

        if (ret != 0)
        {
   
            printf("create thread error:[%s]\n", strerror(ret));
            exit(-1);
        }

        // 设置子线程为分离属性
        pthread_detach(thInfo[index].thread);
    }

    Close(sfd);

    return 0;
}
目录
相关文章
|
10天前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
10天前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
10天前
|
C语言
C语言 网络编程(九)并发的UDP服务端 以线程完成功能
这是一个基于UDP协议的客户端和服务端程序,其中服务端采用多线程并发处理客户端请求。客户端通过UDP向服务端发送登录请求,并根据登录结果与服务端的新子线程进行后续交互。服务端在主线程中接收客户端请求并创建新线程处理登录验证及后续通信,子线程创建新的套接字并与客户端进行数据交换。该程序展示了如何利用线程和UDP实现简单的并发服务器架构。
|
22天前
|
SQL 缓存 自然语言处理
实战案例1:基于C语言的Web服务器实现。
实战案例1:基于C语言的Web服务器实现。
79 15
|
23天前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
55 1
|
26天前
|
C语言
【C语言】多进程服务器
【C语言】多进程服务器
16 4
|
7天前
|
网络协议 数据处理 C语言
利用C语言基于poll实现TCP回声服务器的多路复用模型
此代码仅为示例,展示了如何基于 `poll`实现多路复用的TCP回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。
27 0
|
22天前
|
移动开发 网络协议 编译器
实战案例3:C语言实现的HTTP服务器
实战案例3:C语言实现的HTTP服务器
31 0
|
2天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
5天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。