基于多线程的并发服务器实现

多线程中的线程有两大类:主线程和子线程,分别在服务器端处理监听和通信流程。

主线程:

  • 负责监听,处理客户端的连接请求,即在主线程中循环调用accept()函数。
  • 创建子线程:建立一个新的连接,就创建一个新的子线程,让这个子线程和对应的客户端通信。
  • 回收子线程资源,做线程分离。

子线程:

  • 负责通信,基于主线程建立新连接后得到的文件描述符,和对应的客户端进行数据收发。
  • 发送数据:send()。
  • 接受数据:recv()。

多个线程会共用同一片地址空间,并共享其中的全局数据区、堆区以及内核区的文件描述符等资源,但栈区是每个线程独有的。

在这里插入图片描述
pthread_create用来创建子线程。

服务端代码如下:
(客户端代码见 Linux下的套接字通信

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<strings.h>
#include<arpa/inet.h>
#include<pthread.h>

//信息结构体
struct SockInfo
{
        struct sockaddr_in addr;
        int fd;
};

struct SockInfo infos[512];

void* working(void* arg);

int main()
{
        //创建监听套接字
        int fd = socket(AF_INET,SOCK_STREAM,0);
        if(fd == -1)
        {
                perror("socket");
                return -1;
        }
        //绑定ip 端口号
        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET; //协议簇
        saddr.sin_port = htons(9999); //端口号 主机转网络字节序
        saddr.sin_addr.s_addr = INADDR_ANY; //自动识别IP
        int ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));
        if(ret == -1)
        {
                perror("bind");
                return -1;
        }
        //开始监听
        ret = listen(fd,128);
        if(ret == -1)
        {
                perror("listen");
                return -1;
        }
		//初始化结构体数组
        int max = sizeof(infos) / sizeof(infos[0]);
        for(int i = 0; i < max; ++i)
        {
                bzero(&infos[i],sizeof(infos[i]));
                infos[i].fd = -1;
        }
        //准备接受客户端连接
        int addrlen = sizeof(struct sockaddr_in);
        while(1)
        {
                struct SockInfo* pinfo;
                for(int i = 0; i < max; ++i)
                {
                        if(infos[i].fd == -1)
                        {
                                pinfo = &infos[i];
                                break;
                        }
                }
                int cfd = accept(fd,(struct sockaddr*)&pinfo->addr,&addrlen);
                pinfo->fd = cfd;
                 if(cfd == -1)
                 {
                         perror("accept");
                         break;
                 }
                 //创建子线程
                 pthread_t tid;
                 pthread_create(&tid,NULL,working,pinfo);
                 pthread_detach(tid);
        }
        close(fd);
        return 0;
}
void* working(void* arg)
{
        struct SockInfo* pinfo = (struct SockInfo*)arg;
        //连接成功,打印客户端ip 和 端口号
        char ip[32];
        printf("IP地址:%s,端口:%d\n",
                        inet_ntop(AF_INET,&pinfo->addr.sin_addr.s_addr,ip,sizeof(ip)),
                        ntohs(pinfo->addr.sin_port));
        //通信
        while(1)
        {
                //接收数据
                char buff[1024];
                int len = recv(pinfo->fd,buff,sizeof(buff),0);
                if(len > 0)
                {
                        printf("client data: %s\n",buff);
                        send(pinfo->fd,buff,len,0);
                }
                else if(len == 0)
                {
                        printf("断开连接\n");
                        break;
                }
                else
                {
                        perror("recv");
                        break;
                }
        }
        //结束连接 
        close(pinfo->fd);
        pinfo->fd = -1;
        return NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

库巴巴星人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值