Poll服务器实现框架
#include <头文件>
int main(int argc, char const *argv[])
{
lfd = socket();
bind();
listen();
struct pollfd client[OPEN_MAX]; // 声明pollfd结构体
client[0].fd = lfd; // 要监听的第一个文件描述符
client[0].events = POLLIN; // lfd监听普通读事件
for (int i = 1; i < OPEN_MAX; ++i)
client[i].fd = -1; // 其余表示不可用
int maxi = 0;
while(1)
{
int nready = poll(client, maxi+1, -1); // 阻塞监听是否有客户端连接请求
if (client[0].revents & POLLIN == POLLIN) // lfd有读事件
{
cfd = accept();
for (int i = 1; i < OPEN_MAX; ++i)
{
if (client[i].fd < 0) // 找到空闲区域
{
client[i].fd = cfd; // 存放accept返回的cfd,添加到监听队列中
break;
}
}
// 监听刚刚返回的cfd的读事件
client[i].events = POLLIN;
// 更新最大元素下标
if (i > maxi)
maxi = i;
}
for (i = 1; i <= maxi; ++i) // 轮询所有的文件描述符
{
if (client[i].revents & POLLIN == POLLIN) // client[i]有读事件
/*事务处理*/
}
}
close(lfd);
return 0;
}
Poll服务器实现demo
/* poll server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>
#include <poll.h>
#include<iostream>
// #include "wrap.h"
using namespace std;
#define MAXLINE 1024
#define CLIENTSIZE 1024+1
#define SERV_PORT 2333
void perr_exit(const char* s){
perror(s);
exit(1);
}
int main(int argc, char *argv[])
{
int listenfd ,connfd;
struct pollfd client[CLIENTSIZE];
char buff[MAXLINE];
int maxi = 0;int index;
char str[INET_ADDRSTRLEN]; /* #define INET_ADDRSTRLEN 16 */
socklen_t cliaddr_len;
int nready;
//socket 1
listenfd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
// 设置套接字选项
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in servaddr, cliaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
client[0].fd = listenfd;
client[0].events = POLLIN;
//socket 2
int ret = bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
if(ret <0){perr_exit("bind error");}
printf("ret: %d Server IP: %s Port %d create_socket: %d\n",ret, inet_ntoa(servaddr.sin_addr),ntohs(servaddr.sin_port),listenfd);
//socket 3
ret = listen(listenfd,40);
for (int i = 1; i < CLIENTSIZE; i++)
client[i].fd = -1;
while(1){
nready = poll(client, maxi + 1, -1);
if(nready <0)
exit(-1);
if((client[0].revents& POLLIN == POLLIN)){
cliaddr_len = sizeof(cliaddr);
//socket 4
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
printf("connfd %d\n",connfd);
//use map
for (index = 1; index < CLIENTSIZE; index++)
{
if (client[index].fd < 0)
{
client[index].fd = connfd;
client[index].events = POLLIN;
break;
}
}
/* 是否达到select能监控的文件个数上限 1024 */
if (index == CLIENTSIZE) {
fputs("too many clients\n", stderr);
exit(1);
}
if(index > maxi)
maxi = index;
printf("maxi changed [%d]\n",maxi);
if(--nready == 0)
continue;
} // client[0].revents& POLLIN end
int nlength;
for(int i = 1;i <= maxi;i++){
if( (client[i].fd)<0)
continue;
pollfd sockfd = client[i];
if (sockfd.revents & POLLIN == POLLIN)
{
if ((nlength = read(sockfd.fd, buff, MAXLINE)) == 0)
{
close(sockfd.fd);
client[i].fd = -1;
cout << "客户端关闭 " <<endl;
}
else if(nlength < 0){
//do something
// 收到RST标志
if (errno == ECONNRESET)
{
cout << "连接被重置" << endl;
close(sockfd.fd);
client[i].fd = -1; // poll不再监控该描述符
}
else
perr_exit("read");
}
else
{
for (int j = 0; j < nlength; j++)
buff[j] = toupper(buff[j]);
write(sockfd.fd, buff, nlength); // return client
}
}
if(--nready == 0)
break;
}
}
close(listenfd);
return 0;
}
参考
IO 多路复用之poll