Poll(原理和select一样)【也和select一样 不用话太多的精力】
相比select改进的地方
1.最大文件描述符数量可以 > 1024
2.接受事件和处理事件分开【select是传入传出参数 描述符集合在一起的,需要自己维护一个client数组】
3.但如果链接的client太多效率还是很低【也和select一样是用的轮询机制】要逐个遍历才知道 那些client有事件产生
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */ 接收事件
short revents; /* returned events */ 返回事件
};
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout); 第二个参数 和select类似的 都是最大文件描述符+1 ,高速内核要处理多少个文件描述符
#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;
}