在这篇文章中虽然实现了能够和多客户端建立连接,并且同时和多个客户端进行通信。
基于多反应堆的高并发服务器【C/C++/Reactor】(上)-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/135141316?spm=1001.2014.3001.5501但是有一个问题(O_O)?:这个程序它是单线程的。如果我们想要程序的效率更高一些,就需要使用多线程。
研究一下:若使用多线程,需要在什么地方把子线程创建出来
在服务器端有两类文件描述符:一类是用于通信的,一类是用于监听的
关于监听的文件描述符,在服务器端有且仅有一个。所以我们把它在主线程里边创建出来之后,就不需要做其他的监听的文件描述符的创建了。通过这一个唯一的监听文件描述符,服务器就能接收到客户端的连接请求,并且和多个客户端建立连接
int epollRun(int lfd) {
...
while(1) {
int num = epoll_wait(epfd,evs,size,-1);
if(num == -1) {
perror("epoll_wait");
return -1;
}
for(int i=0;i<num;++i) {
int fd = evs[i].data.fd;
if(fd == lfd) {
// 建立新连接 accept
acceptClient(lfd,epfd);
}else{
// 主要是接收对端的数据
recvHttpRequest(fd,epfd);
}
}
}
return 0;
}
在epollRun函数中,在while循环里边,需要判断文件描述符的类型,如果是监听的文件描述符,它的读事件被触发了。那么我们就和客户端建立新连接。还有一种情况是通信的文件描述符,我们就需要和客户端进行通信。因此不管是建立连接还是和客户端通信,都可以把它放到一个子线程里面去做。也就是说我们需要在这两个函数调用的位置分别创建子线程。把acceptClient函数或者是recvHttpRequest函数传递给子线程,让子线程去执行这个处理动作。
int epollRun(int lfd) {
// 1.创建epoll实例
int epfd = epoll_create(1);
if(epfd == -1) {
perror("epoll_create");
return -1;
}
// 2.添加监听fd lfd上树 对于监听的描述符来说只需要看一下有没有新的客户端连接
struct epoll_event ev;
ev.data.fd = lfd;
ev.events = EPOLLIN;// 委托epoll(内核)帮我们检测lfd的读事件
int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev);
if(ret == -1) {
perror("epoll_ctl");
return -1;
}
// 3.检测
struct epoll_event evs[1024];
// int size = sizeof(evs)/sizeof(epoll_event);
int size = sizeof(evs)/sizeof(evs[0]);
while(1) {
int num = epoll_wait(epfd,evs,size,-1);
if(num == -1) {
perror("epoll_wait");
return -1;
}
for(int i=0;i<num;++i) {
struct FdInfo* info = (struct FdInfo*)malloc(sizeof(struct FdInfo));
int fd = evs[i].data.fd;
info->epfd = epfd;
info->fd = fd;
if(fd == lfd) {
// 建立新连接 accept
// acceptClient(lfd,epfd);// 两个参数
// 两个参数->只能够对数据进行封装
pthread_create(&info->tid,NULL,acceptClient,info);
}else{
// 主要是接收对端的数据
// recvHttpRequest(fd,epfd);
// 子线程被创建出来后,它对应的处理动作是 recvHttpRequest,给这个函数传递的实参是
// info这个结构体里边的数据
pthread_create(&info->tid,NULL,recvHttpRequest,info);
}
}
}
return 0;
}
接下来要做的事情就是把acceptClient函数和recvHttpRequest函数原型修改一下。因为对于一个子线程来说,它的回调函数对应的是一个函数指针,函数指针的返回值是void*类型。它的参数也是void*类型。先切换到头文件,修改头文件。
Server.h
修改前:
// 和客户端建立连接
int acceptClient(int lfd,int epfd);
// 主要是接收对端的数据
int recvHttpRequest(int cfd,int epfd);
修改后:
// 和客户端建立连接
void* acceptClientThread(void* arg);
// 主要是接收对端的数据
void* recvHttpRequest(void* arg);
未完待续~