【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;
}
目录
相关文章
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
41 2
|
2月前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
2月前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
3月前
|
SQL 缓存 自然语言处理
实战案例1:基于C语言的Web服务器实现。
实战案例1:基于C语言的Web服务器实现。
178 15
|
2月前
|
C语言
C语言 网络编程(九)并发的UDP服务端 以线程完成功能
这是一个基于UDP协议的客户端和服务端程序,其中服务端采用多线程并发处理客户端请求。客户端通过UDP向服务端发送登录请求,并根据登录结果与服务端的新子线程进行后续交互。服务端在主线程中接收客户端请求并创建新线程处理登录验证及后续通信,子线程创建新的套接字并与客户端进行数据交换。该程序展示了如何利用线程和UDP实现简单的并发服务器架构。
|
3月前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
79 1
|
2月前
|
网络协议 数据处理 C语言
利用C语言基于poll实现TCP回声服务器的多路复用模型
此代码仅为示例,展示了如何基于 `poll`实现多路复用的TCP回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。
77 0
|
3月前
|
移动开发 网络协议 编译器
实战案例3:C语言实现的HTTP服务器
实战案例3:C语言实现的HTTP服务器
132 0
|
24天前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
37 1
C++ 多线程之初识多线程
|
9天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
11 3