#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include <ctype.h>
int main()
{
// 1 创建套接字
int lfd = socket(AF_INET, SOCK_STREAM, 0);
// 2 端口复用
int opt = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 3 绑定
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(lfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
// 4 同时访问上限
listen(lfd, 128);
// 5 创建epoll句柄
int epfd = epoll_create(1000);
// lfd结点上树
struct epoll_event tep;
tep.data.fd = lfd;
tep.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tep);
// 6 监听读事件
int cfd; // 定义lfd通信描述符
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr); // 用于接收客户端信息
struct epoll_event ep[1000]; // 用于接收变化的结点
while(1)
{
int nready = epoll_wait(epfd, ep, 1000, -1); // 阻塞等待结点变化
for(int i = 0; i < nready; i++)
{
if(!(ep[i].events & EPOLLIN))
continue; // 因为只要有事件发生,就会计入ep[]中,如果不是读事件,继续循环
if(ep[i].data.fd == lfd)
{
// 是连接请求
cfd = accept(lfd, (struct sockaddr*)&client_addr, &client_len);
char ip[16] = {0};
printf("conn from %s at %d\n", inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(client_addr.sin_port)); // 打印客户端信息
// cfd 上树
tep.data.fd = cfd;
tep.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tep);
}
else
{
// 普通读事件
int sockfd = ep[i].data.fd;
char buf[BUFSIZ] = {0};
int n = read(sockfd, buf, sizeof(buf));
if(n < 0)
{
perror("read err");
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL); // 下树
close(sockfd);
}
else if(n == 0)
{
printf("client[%d] closed\n", sockfd);
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL); // 下树
close(sockfd);
}
else
{
write(sockfd, buf, n);
write(STDOUT_FILENO,buf, n);
}
} // 普通读事件结束
} // for循环,解决变化结点事件结束
} // while循环结束
close(lfd);
close(epfd);
return 0;
}
epoll 版 高并发服务器
最新推荐文章于 2023-06-14 16:29:40 发布