用epoll()实现并发服务器通信
服务器端代码
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/epoll.h>
int main(){
//创建socket
int lfd = socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in saddr;
saddr.sin_port = htons(9999);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
//绑定
bind(lfd,(struct sockaddr*)&saddr,sizeof(saddr));
//监听
listen(lfd,8);
//调用epoll_creat()创建一个epoll实例
int epfd = epoll_create(100);
//将监听的文件描述符添加到epoll实例的rbr中
struct epoll_event epev;
epev.events = EPOLLIN;
epev.data.fd = lfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);
struct epoll_event epevs[1024];
while(1){
int ret = epoll_wait(epfd,epevs,1024,-1);
if(ret == -1){
perror("epoll_wait");
exit(-1);
}
// printf("ret = %d\n",ret);//将客户端中sleep(1)改为usleep(1000)可以看到ret = 2
for(int i = 0; i < ret; i++){
if(epevs[i].data.fd == lfd){
//监听的文件描述符,有客户端连接
struct sockaddr_in caddr;
int len = sizeof(caddr);
int cfd = accept(lfd,(struct sockaddr*)&caddr,&len);
char cIp[32];
printf("有新客户端连接,IP : %s,port : %d\n",
inet_ntop(AF_INET,&caddr.sin_addr.s_addr,cIp,sizeof(cIp)),
ntohs(caddr.sin_port));
epev.events = EPOLLIN;//epev.events = EPOLLIN | EPOLLOUT
epev.data.fd = cfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);
}else{
if(epevs[i].events & EPOLLOUT){//检测的有写入数据
continue;
}
//检测到有读数据到达,需要通信
char buf[1024] = {0};
int len = read(epevs[i].data.fd,buf,sizeof(buf));
if(len == -1){
perror("read");
exit(-1);
}else if(len == 0){
printf("client closed...");
close(epevs[i].data.fd);
epoll_ctl(epfd,EPOLL_CTL_DEL,epevs[i].data.fd,NULL);
}else if(len > 0){
printf("read buf: %s\n",buf);
write(epevs[i].data.fd,buf,strlen(buf)+1);
}
}
}
}
close(lfd);
close(epfd);
return 0;
}
客户端代码
//客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(){
//创建套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd == -1){
perror("socket");
exit(-1);
}
//连接服务器
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
inet_pton(AF_INET,"192.168.245.128",&saddr.sin_addr.s_addr);
saddr.sin_port = htons(9999);
int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret == -1){
perror("connect");
exit(-1);
}
//通信
char recvBuf[1024] = {0};
int i = 0;
while(1){
sprintf(recvBuf,"data : %d\n",i++);
write(fd,recvBuf,strlen(recvBuf));
int len = read(fd,recvBuf,sizeof(recvBuf));
if(len == -1){
perror("read");
exit(-1);
}else if(len > 0){
printf("recv server data : %s\n",recvBuf);
}else if(len == 0){
printf("server closed...");
break;
}
//sleep(1);
usleep(1000);
}
return 0;
}
运行效果图
服务端
客户端1
客户端2
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人