#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
// #include <winsock2.h>
// #include <mswsock.h>
// #include <windows.h>
// #include <sys/types.h>
// #include <unistd.h>
// #include <fcntl.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>
#define BUFFER_LENGTH 1024
#define EPOLL_SIZE 1024
#define MAX_PORT 100
int islistenfd(int fd,int *fds){
int i=0;
for (i=0;i<MAX_PORT;i++){
if(fd==*(fds+i)) return fd;
}
return 0;
}
int main(int argc,char *argv[]){
if (argc < 2) {
printf("Param Error \n");
return -1;
}
int port=atoi(argv[1]);//开始的端口
int sockfds[MAX_PORT]={0}; //lisiten fd
int epfd=epoll_create(1);
int i=0;
for(i=0;i<MAX_PORT;i++){
int sockfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
memset(&addr,0,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(port+i); //8888 ---> 8889 ----> 8890 ----> ....
addr.sin_addr.s_addr=INADDR_ANY;
if (bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in))<0){
perror("bind");
return -2;
}
if(listen(sockfd,5)<0){
perror("listen");
return -3;
}
printf("tcp server listen on port : %d\n", port + i);
struct epoll_event ev;
ev.events=EPOLLIN;
ev.data.fd = sockfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
sockfds[i]=sockfd;
}
struct epoll_event events[EPOLL_SIZE] = {0}; //创建一个结构体数组 events 用于存储 epoll_wait() 返回的事件列表。
while (1){
int nready=epoll_wait(epfd,events,EPOLL_SIZE,5); //
if (nready == -1) continue; //表示5秒内,没有事件,继续监听
int i=0;
for (i=0;i<nready;i++){
int sockfd=islistenfd(events[i].data.fd ,sockfds);
if(sockfd){
struct sockaddr_in client_addr;
memset(&client_addr,0,sizeof(struct sockaddr_in));
socklen_t client_len =sizeof(client_addr);
int clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&client_len);
fcntl(clientfd,F_SETFL,O_NONBLOCK);
int reuse=1;
setsockopt(clientfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
struct epoll_event ev;
ev.events=EPOLLIN | EPOLLET; //EPOLLET 则表示将 I/O 事件设置为边缘触发模式。
ev.data.fd=clientfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&ev);
}
else{
//当某个客户端套接字上出现可读事件时(即该文件描述符在 events 中对应的元素有 EPOLLIN 标志),则调用 recv() 函数从该套接字中读取数据
int clientfd=events[i].data.fd;
char buffer[BUFFER_LENGTH]={0};
int len=recv(clientfd,buffer,BUFFER_LENGTH,0);
if (len < 0){//出现了异常情况或者非阻塞状态下没有更多数据可读
//关闭该套接字并将其从 epoll 实例中删除
close(clientfd);
struct epoll_event ev;
ev.events=EPOLLIN;
ev.data.fd=clientfd;
epoll_ctl(epfd,EPOLL_CTL_DEL,clientfd,&ev); //从 epoll 实例中删除 clientfd 对应的文件描述符,并且停止监听该套接字上的事件。
}
else if(len == 0) {//对方已经断开连接
//关闭该套接字并将其从 epoll 实例中删除
close(clientfd);
struct epoll_event ev;
ev.events=EPOLLIN;
ev.data.fd=clientfd;
epoll_ctl(epfd,EPOLL_CTL_DEL,clientfd,&ev);
}
else{
printf("Recv: %s, %d byte(s), clientfd: %d\n", buffer, len, clientfd);
}
}
}
}
return 0;
}