3. Poll
前面我们讲到Select的劣势:
- rset不可重用,每次都会产生一个新的rset
- 用户态到内核态整体拷贝仍有较大开销
- 每次遍历fd数组,都需要o(n)的时间复杂度
- rset这个bitmap是有上限的,默认是1024
3.1 Poll实例
那么Poll其实就是为了优化部分劣势的,我们也给出一个Poll的例子:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <wait.h>
#include <signal.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <sys/poll.h>
#define MAXBUF 256
void child_process(void)
{
sleep(2);
char msg[MAXBUF];
struct sockaddr_in addr = {0};
int n, sockfd,num=1;
srandom(getpid());
/* Create socket and connect to server */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = 16777343;
connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
printf("child {%d} connected \n", getpid());
while(1){
int sl = (random() % 10 ) + 1;
num++;
sleep(sl);
sprintf (msg, "Test message %d from client %d", num, getpid());
n = write(sockfd, msg, strlen(msg)); /* Send message */
}
}
int main()
{
char buffer[MAXBUF];
int fds[5];
struct sockaddr_in addr;
struct sockaddr_in client;
int addrlen, n,i,max=0;;
int sockfd, commfd;
for(i=0;i<5;i++)
{
if(fork() == 0)
{
child_process();
exit(0);
}
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd,(struct sockaddr*)&addr ,sizeof(addr));
listen (sockfd, 5);
//前面都和select一样,后面是poll和select不一样的地方,这里主要用了一个pollfd的结构体数组
pollfd polls[5];
for (i=0;i<5;i++)
{
memset(&client, 0, sizeof (client));
addrlen = sizeof(client);
//赋值fd
polls[i].fd= accept(sockfd, (struct sockaddr*)&client, reinterpret_cast<socklen_t *>(&addrlen));
//设置要关心的事件
polls[i].events = POLLIN;
}
sleep(1);
while(1){
puts("round again");
//poll,将Polls传进去,监听五个fd,超时5s
poll(polls,5,5000);
for(i=0;i<5;i++) {
if(polls[i].revents & POLLIN){
//重置事件
polls[i].revents = 0;
//重置buffer
memset(buffer,0,MAXBUF);
//读fd
read(polls[i].fd, buffer, MAXBUF);
puts("round again111");
puts(buffer);
}
}
}
return 0;
}
那么我们可以看到,这里解决了如下两个问题:
- rset不可重用,每次都会产生一个新的rset
- rset这个bitmap是有上限的,默认是1024
在内核的操作上,这两个是一样的,都是集体的拷贝。
那还剩余两个问题:
- 内核态到用户态的拷贝消耗
- 每次都需要遍历都需要o(n)的时间复杂度