C++ 网络编程代码解析(更新了poll和epoll多路复用)
客户端代码(client.cpp)
#include"../myhead.h"#defineSER_IP"xxx"// 服务器IP地址#defineSER_PORT8888// 服务器端口号#defineCLI_IP"xxx"// 客户端IP地址#defineCLI_PORT9999// 客户端端口号intmain(){// 创建UDP套接字intcfd=socket(AF_INET,SOCK_DGRAM,0);if(cfd==-1){perror("socket error");return-1;}printf("socket success\n");// 绑定客户端地址和端口structsockaddr_incin;cin.sin_family=AF_INET;cin.sin_port=htons(CLI_PORT);cin.sin_addr.s_addr=inet_addr(CLI_IP);if(bind(cfd,(structsockaddr*)&cin,sizeof(cin))==-1){perror("bind error");return-1;}printf("bind success\n");// 设置服务器地址信息structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);socklen_t socklen=sizeof(sin);charwbuf[128]="";while(1){bzero(wbuf,sizeof(wbuf));fgets(wbuf,sizeof(wbuf),stdin);// 从标准输入读取数据wbuf[strlen(wbuf)-1]=0;// 去除换行符// 发送数据到服务器if(sendto(cfd,wbuf,sizeof(wbuf),0,(structsockaddr*)&sin,socklen)==-1){perror("sendto error");return-1;}// 接收服务器响应if(recvfrom(cfd,wbuf,sizeof(wbuf),0,(structsockaddr*)&sin,&socklen)==-1){perror("recvfrom error");return-1;}printf("[%s:%d]:%s\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),wbuf);printf("发送成功\n");}close(cfd);}功能说明
这是一个UDP客户端程序,实现了以下功能:
- 创建UDP套接字
- 绑定客户端本地地址和端口
- 从标准输入读取用户输入
- 发送数据到指定的UDP服务器
- 接收服务器返回的响应数据
- 打印服务器响应信息
基础UDP服务端(server.cpp)
#include"../myhead.h"#defineSER_IP"xxx"// 服务器IP地址#defineSER_PORT8888// 服务器端口号intmain(){// 创建UDP套接字intsfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket error");return-1;}// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}structsockaddr_incin;socklen_t socklen=sizeof(cin);charrbuf[128]="";while(1){bzero(rbuf,sizeof(rbuf));// 接收客户端数据if(recvfrom(sfd,rbuf,sizeof(rbuf),0,(structsockaddr*)&cin,&socklen)==-1){perror("recvfrom error");return-1;}printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);// 在收到的消息后添加"*_*"标识strcat(rbuf,"*_*");// 发送响应数据给客户端if(sendto(sfd,rbuf,sizeof(rbuf),0,(structsockaddr*)&cin,socklen)==-1){perror("sendto error");return-1;}printf("发送成功\n");}close(sfd);}功能说明
这是一个基础的UDP服务端程序,实现了以下功能:
- 创建UDP套接字
- 绑定服务器地址和端口
- 接收客户端发送的数据
- 打印客户端地址和收到的消息
- 在消息后添加"_"标识
- 发送响应数据给客户端
多进程TCP服务端(server_morecli.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号// 信号处理函数,用于回收子进程资源voidhandler(intsign){while(waitpid(-1,NULL,WNOHANG)>0);}intmain(){// 设置信号处理,防止僵尸进程if(signal(SIGCHLD,handler)==SIG_ERR){perror("signal error");return-1;}// 创建TCP套接字intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");// 监听客户端连接请求if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);while(1){// 接受客户端连接intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:已连接成功,newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);// 创建子进程处理客户端请求pid_t pid=fork();if(pid>0){close(newfd);// 父进程关闭newfd}elseif(pid==0){close(sfd);// 子进程关闭sfdcharrbuf[128]="";while(1){bzero(rbuf,sizeof(rbuf));intres=recv(newfd,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");break;}strcat(rbuf,"*_*");if(send(newfd,rbuf,sizeof(rbuf),0)==-1){perror("send error");return-1;}printf("发送成功\n");}close(newfd);exit(EXIT_SUCCESS);}else{perror("fork error");return-1;}}close(sfd);}功能说明
这是一个多进程TCP服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 使用fork()创建子进程处理每个客户端连接
- 子进程负责与客户端进行数据交互
- 使用信号处理函数回收子进程资源,防止僵尸进程
多路复用TCP服务端(server_IO_select.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号intmain(){// 创建TCP套接字intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");// 监听客户端连接请求if(listen(sfd,128)==-1){perror("listen error");}structsockaddr_incin;socklen_t socklen=sizeof(cin);// 初始化文件描述符集合fd_set readfds,tempfds;FD_ZERO(&readfds);FD_SET(0,&readfds);// 监听标准输入FD_SET(sfd,&readfds);// 监听sfdintmaxfd=sfd;intnewfd=-1;structsockaddr_incin_arr[1024];// 保存客户端地址信息while(1){tempfds=readfds;// 调用select函数监听文件描述符intres=select(maxfd+1,&tempfds,NULL,NULL,NULL);if(res==-1){perror("select error");return-1;}elseif(res==0){printf("time out\n");return-1;}// 处理新客户端连接if(FD_ISSET(sfd,&tempfds)){newfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));cin_arr[newfd]=cin;FD_SET(newfd,&readfds);if(maxfd<newfd){maxfd=newfd;}}// 处理标准输入事件if(FD_ISSET(0,&tempfds)){charwbuf[128]="";fgets(wbuf,sizeof(wbuf),stdin);printf("触发了输入事件:%s\n",wbuf);// 向所有客户端发送消息for(inti=4;i<=maxfd;i++){send(i,wbuf,strlen(wbuf),0);}}// 处理客户端数据for(inti=4;i<=maxfd;i++){if(FD_ISSET(i,&tempfds)){charrbuf[128]="";bzero(rbuf,sizeof(rbuf));intres=recv(i,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");close(i);FD_CLR(i,&readfds);// 更新maxfdfor(intk=maxfd;i>=0;k--){if(FD_ISSET(k,&readfds)){maxfd=k;break;}}continue;}printf("[%s:%d]:%s\n",inet_ntoa(cin_arr[i].sin_addr),ntohs(cin_arr[i].sin_port),rbuf);strcat(rbuf,"*_*");if(send(i,rbuf,strlen(rbuf),0)==-1){perror("send error");return-1;}printf("发送成功\n");}}}close(sfd);}功能说明
这是一个使用select多路复用的TCP服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 使用select函数实现多路复用,同时监听多个文件描述符
- 处理新客户端连接
- 处理客户端发送的数据
- 支持服务器端向所有客户端广播消息
- 客户端下线时及时清理资源
多路复用TCP服务端(server_IO_poll.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"#defineSER_PORT8888#defineMAX_FDS1024intmain(intargc,constchar*argv[]){intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);structpollfdfds[MAX_FDS];for(inti=0;i<MAX_FDS;i++){fds[i].fd=-1;fds[i].events=0;fds[i].revents=0;}fds[sfd].fd=sfd;fds[sfd].events=POLLIN;charrbuf[128]="";while(1){intnfds=poll(fds,MAX_FDS,-1);if(nfds==-1){perror("poll error");break;}for(inti=0;i<MAX_FDS;i++){if(fds[i].fd==-1){continue;}if(!(fds[i].revents&POLLIN)){continue;}if(fds[i].fd==sfd){intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");continue;}printf("[%s:%d]:连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));for(intj=0;j<MAX_FDS;j++){if(fds[j].fd==-1){fds[j].fd=newfd;fds[j].events=POLLIN;break;}}}else{intcfd=fds[i].fd;bzero(rbuf,sizeof(rbuf));intres=recv(cfd,rbuf,sizeof(rbuf),0);if(res==-1){perror("recv error");close(cfd);fds[i].fd=-1;continue;}if(res==0){printf("对端已下线\n");close(cfd);fds[i].fd=-1;continue;}printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);strcat(rbuf,"*_*");if(send(cfd,rbuf,sizeof(rbuf),0)==-1){perror("send error");close(cfd);fds[i].fd=-1;}else{printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);}}}}close(sfd);}功能说明
这是一个使用poll多路复用的TCP服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 使用poll函数实现多路复用,同时监听多个文件描述符
- 处理新客户端连接
- 处理客户端发送的数据
- 客户端下线时及时清理资源
多路复用TCP服务端(server_IO_epoll.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"#defineSER_PORT8888intmain(intargc,constchar*argv[]){intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);intepfd=epoll_create(1);if(epfd==-1){perror("epoll_create error");return-1;}structepoll_eventev;ev.events=EPOLLIN;ev.data.fd=sfd;epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&ev);structepoll_eventevs[1024];intsize=sizeof(evs)/sizeof(evs[0]);while(1){intnum=epoll_wait(epfd,evs,size,-1);printf("num=%d\n",num);for(inti=0;i<num;i++){intfd=evs[i].data.fd;if(fd==sfd){intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:已连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));structepoll_eventev;ev.events=EPOLLIN;ev.data.fd=newfd;epoll_ctl(epfd,EPOLL_CTL_ADD,newfd,&ev);}else{charrbuf[128]="";bzero(rbuf,sizeof(rbuf));intres=recv(fd,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);close(fd);break;}printf("收到的数据为:%s\n",rbuf);strcat(rbuf,"*_*");if(send(fd,rbuf,sizeof(rbuf),0)==-1){perror("send error");return-1;}printf("发送成功\n");}}}close(sfd);close(epfd);}功能说明
这是一个使用epoll多路复用的TCP服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 使用epoll函数实现多路复用,同时监听多个文件描述符
- 处理新客户端连接
- 处理客户端发送的数据
- 客户端下线时及时清理资源
多线程TCP服务端(server_tokcli.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号// 客户端信息结构体structInfo{intnewfd;structsockaddr_incin;};// 线程函数,处理客户端请求void*deal_cli_msg(void*arg){intnewfd=((structInfo*)arg)->newfd;structsockaddr_incin=((structInfo*)arg)->cin;charrbuf[128]="";while(1){bzero(rbuf,sizeof(rbuf));intres=recv(newfd,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");break;}printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);strcat(rbuf,"*_*");if(send(newfd,rbuf,sizeof(rbuf),0)==-1){perror("send error");returnNULL;}printf("发送成功\n");}close(newfd);pthread_exit(NULL);}intmain(){// 创建TCP套接字intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");// 监听客户端连接请求if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);while(1){// 接受客户端连接intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:已连接成功,newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);// 创建线程处理客户端请求structInfobuf={newfd,cin};pthread_t tid=-1;if(pthread_create(&tid,NULL,deal_cli_msg,&buf)!=0){printf("pthread_create error\n");return-1;}pthread_detach(tid);// 线程分离,自动回收资源}close(sfd);}功能说明
这是一个多线程TCP服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 使用pthread_create()创建线程处理每个客户端连接
- 线程负责与客户端进行数据交互
- 使用pthread_detach()实现线程分离,自动回收线程资源
TCP客户端(recv.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号#defineCLI_IP"192.168.116.200"// 客户端IP地址#defineCLI_PORT9999// 客户端端口号intmain(){// 创建TCP套接字intcfd=socket(AF_INET,SOCK_STREAM,0);if(cfd==-1){perror("socket error");return-1;}printf("socket success\n");// 绑定客户端地址和端口structsockaddr_incin;cin.sin_family=AF_INET;cin.sin_port=htons(CLI_PORT);cin.sin_addr.s_addr=inet_addr(CLI_IP);if(bind(cfd,(structsockaddr*)&cin,sizeof(cin))==-1){perror("bind error");return-1;}printf("bind success\n");// 设置服务器地址信息structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);// 连接到服务器if(connect(cfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("connect error");return-1;}printf("connect success\n");charwbuf[128]="";while(1){bzero(wbuf,sizeof(wbuf));fgets(wbuf,sizeof(wbuf),stdin);// 从标准输入读取数据wbuf[strlen(wbuf)-1]=0;// 去除换行符// 发送数据到服务器if(send(cfd,wbuf,sizeof(wbuf),0)==-1){perror("send error");return-1;}// 接收服务器响应if(recv(cfd,wbuf,sizeof(wbuf),0)==-1){perror("recv error");return-1;}printf("%s\n",wbuf);printf("发送成功\n");}close(cfd);}功能说明
这是一个TCP客户端程序,与send.cpp配套使用,实现了以下功能:
- 创建TCP套接字
- 绑定客户端本地地址和端口
- 连接到指定的TCP服务器
- 从标准输入读取用户输入
- 发送数据到服务器
- 接收服务器返回的响应数据
- 打印服务器响应信息
TCP服务端(send.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号intmain(){// 创建TCP套接字intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");// 监听客户端连接请求if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);// 接受客户端连接intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:已连接成功,newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);charrbuf[128]="";while(1){bzero(rbuf,sizeof(rbuf));intres=recv(newfd,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");break;}printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);// 在收到的消息后添加"*_*"标识strcat(rbuf,"*_*");// 发送响应数据给客户端if(send(newfd,rbuf,sizeof(rbuf),0)==-1){perror("send error");return-1;}printf("发送成功\n");}close(newfd);close(sfd);}功能说明
这是一个基础的TCP服务端程序,与recv.cpp配套使用,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 接受客户端连接
- 接收客户端发送的数据
- 打印客户端地址和收到的消息
- 在消息后添加"_"标识
- 发送响应数据给客户端
TCP循环服务端(server_for.cpp)
#include"../myhead.h"#defineSER_IP"192.168.116.200"// 服务器IP地址#defineSER_PORT8888// 服务器端口号intmain(){// 创建TCP套接字intsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd=%d\n",sfd);// 绑定服务器地址和端口structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(structsockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return-1;}printf("bind success\n");// 监听客户端连接请求if(listen(sfd,128)==-1){perror("listen error");return-1;}printf("listen success\n");structsockaddr_incin;socklen_t socklen=sizeof(cin);// 循环接受客户端连接while(1){intnewfd=accept(sfd,(structsockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return-1;}printf("[%s:%d]:已连接成功,newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);charrbuf[128]="";while(1){bzero(rbuf,sizeof(rbuf));intres=recv(newfd,rbuf,sizeof(rbuf),0);if(res==0){printf("对端已下线\n");break;}printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);// 在收到的消息后添加"*_*"标识strcat(rbuf,"*_*");// 发送响应数据给客户端if(send(newfd,rbuf,sizeof(rbuf),0)==-1){perror("send error");return-1;}printf("发送成功\n");}close(newfd);}close(sfd);}功能说明
这是一个TCP循环服务端程序,实现了以下功能:
- 创建TCP套接字
- 绑定服务器地址和端口
- 监听客户端连接请求
- 循环接受客户端连接
- 处理单个客户端请求,直到客户端下线
- 接收客户端发送的数据
- 打印客户端地址和收到的消息
- 在消息后添加"_"标识
- 发送响应数据给客户端
代码总结
文件配套关系
- UDP通信:client.cpp(UDP客户端)与server.cpp(基础UDP服务端)配套使用
- TCP通信:recv.cpp(TCP客户端)与send.cpp(基础TCP服务端)配套使用
服务端实现类型
- 基础UDP服务端(server.cpp):简单的单进程UDP服务端
- 基础TCP服务端(send.cpp):简单的单进程TCP服务端
- TCP循环服务端(server_for.cpp):循环接受客户端连接的TCP服务端
- 多进程TCP服务端(server_morecli.cpp):使用fork()创建子进程处理每个客户端连接
- 多线程TCP服务端(server_tokcli.cpp):使用pthread_create()创建线程处理每个客户端连接
- 多路复用TCP服务端(server_IO_select.cpp):使用select函数实现多路复用,单进程处理多个客户端连接
- 多路复用TCP服务端(server_IO_poll.cpp):使用poll函数实现多路复用,单进程处理多个客户端连接
- 多路复用TCP服务端(server_IO_epoll.cpp):使用epoll函数实现多路复用,单进程处理多个客户端连接
通信方式对比
- UDP:无连接、不可靠、传输速度快,适合对实时性要求高的场景
- TCP:面向连接、可靠、传输速度相对较慢,适合对数据完整性要求高的场景
服务端实现方式对比
- 基础服务端:简单的单进程服务端,只能处理一个客户端连接,适合测试和简单应用
- 循环服务端:循环接受客户端连接,处理完一个客户端请求后再处理下一个,适合客户端连接数较少的场景
- 多进程服务端:使用fork()创建子进程处理每个客户端连接,资源开销较大,但稳定性较好
- 多线程服务端:使用线程处理每个客户端连接,资源开销较小,适合客户端连接数较多的场景
- 多路复用服务端:单进程处理多个客户端连接,资源开销最小,适合客户端连接数非常多的场景
- select:传统的多路复用方式,存在文件描述符数量限制(默认1024),每次调用需要重新拷贝文件描述符集合
- poll:改进的多路复用方式,没有文件描述符数量限制,但每次调用仍需要重新拷贝文件描述符集合
- epoll:高效的多路复用方式,没有文件描述符数量限制,采用事件驱动机制,无需每次拷贝文件描述符集合
适用场景
- UDP:视频通话、实时游戏、广播消息等
- TCP:文件传输、网页浏览、邮件发送等
- 基础服务端:测试环境、简单应用
- 循环服务端:客户端连接数较少的场景
- 多进程:服务器性能较好,客户端连接数较少的场景
- 多线程:服务器性能一般,客户端连接数较多的场景
- 多路复用:服务器性能有限,客户端连接数非常多的场景