Poll (the principle is the same as select) [the same as select without too much energy]
Compared with select
1. The maximum number of file descriptors can be> 1024
2. Receive events and process events separately [ select is a collection of incoming and outgoing parameters and descriptors, and you need to maintain a client array by yourself ]
3. But if there are too many clients connected, the efficiency is still very low [ also the same polling mechanism as select ] It is necessary to traverse one by one to know that those clients have events
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ Receive events short revents; /* returned events */ Return events };
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout); The second parameter, similar to select, is the maximum file descriptor +1, how many file descriptors the high-speed kernel has to process
#include <iostream>
#include <poll.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
#define SERVER_PORT 8888
#define MAX_LINE 512
#define OPEN_MAX 1024
static int Debug = 1;
int
main(int argc, char*argv[])
{
int i, j, maxi, listenfd, connfd, sockfd;
int nready;
ssize_t n;
char buf[MAX_LINE], str[INET_ADDRSTRLEN];
socklen_t clie_addr_len;
struct pollfd client[OPEN_MAX];
struct sockaddr_in clie_addr, serv_addr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVER_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, OPEN_MAX);
client[0].fd = listenfd;
client[0].events = POLLIN;
for(i=1; i<OPEN_MAX; i++)
client[i].fd = -1;
maxi = 0;
if(Debug)printf("-----listening-----\n");
while(true){
nready = poll(client, maxi+1, -1);
if(client[0].revents & POLLIN){ // if has client connect
clie_addr_len = sizeof(clie_addr);
connfd = accept(listenfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
// print client IP and PORT
if(Debug)printf("client IP:%s, PORT:%d \n",
inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
ntohs(clie_addr.sin_port));
for(i=1; i<OPEN_MAX; i++){ // save connfd to fds
if(client[i].fd < 0){
client[i].fd = connfd;
break;
}
}
if(i == OPEN_MAX){
perror("connect client too many");
exit(1);
}
client[i].events = POLLIN; // listening connfd read event
if(i > maxi)
maxi = i;
if(--nready == 0)
continue;
}
for(i=1; i<=maxi; i++){
if((sockfd = client[i].fd) < 0)
continue;
if(client[i].revents & POLLIN){
if((n = read(sockfd, buf, sizeof(buf))) < 0){
if(errno == ECONNRESET){ /*RST分节*/
if(Debug)printf("client[%d] abort connection \n", i);
close(sockfd);
client[i].fd = -1;
}else{
perror("read error");
close(sockfd);
client[i].fd = -1;
}
}else if(n == 0){
if(Debug)printf("client[%d] closed connection\n", i);
close(sockfd);
client[i].fd = -1;
}else{
if(errno == EINTR){
if(Debug)printf("client[%d] read is interupted by signal\n", i);
close(sockfd);
client[i].fd = -1;
if(--nready == 0)break;
else continue;
}
for(j=0; j<n; j++)
buf[j] = toupper(buf[j]);
write(sockfd, buf, n);
if(Debug)printf("server has reply client\n");
if(--nready == 0)break;
}
}
}
}
return 0;
}