多路IO转接 poll模型

poll模型与select模型大同小异,也是一种轮询模型,不同之处是poll模型更加方便,不像select模型一样,每次都去设置fd_set的值,select模型最多能打开的文件描述符为1024个,即使使用ulimit -n xxx也无法改变,但是poll模型可以突破1024的限制,只需更改系统的ulimit -n配置即可。

#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <errno.h>
#define TCP_PORT 9999
#define SOCK_NUM 2048
int main()
{
    struct pollfd socketfd[SOCK_NUM];
    int socket_ser,socket_accept;
    struct sockaddr_in addr,addr_c;
    int maxfd;
    char recbuf[1500];
    socket_ser = socket(AF_INET,SOCK_STREAM,0);
    bzero(&addr,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(TCP_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    bind(socket_ser,(struct sockaddr *)&addr,sizeof(addr));
    listen(socket_ser,128);
    socketfd[0].fd = socket_ser;
    socketfd[0].events = POLL_IN;
    for (int j = 1; j < SOCK_NUM; ++j) {
        socketfd[j].fd = -1;
    }
    maxfd = 0;


    while (1)
    {
        //监听maxfd+1个文件描叙符的读
        int num = poll(socketfd,maxfd+1,-1);//-1代表阻塞;
        if (socketfd[0].revents & POLLIN)
        {
            int i;
            for (i = 1; i < SOCK_NUM; ++i) {
                if(socketfd[i].fd<0)
                    break;
            }
            bzero(&addr_c,sizeof(addr_c));
            int len = sizeof(addr_c);
            socketfd[i].fd = accept(socket_ser,(struct sockaddr*)&addr_c,(socklen_t*)&len);
            if (i > maxfd)
            {
                maxfd = i;
            }
            socketfd[i].events = POLLIN;
            num--;
            char recip[16];
            printf("Ip is %s,Port is %d\n",inet_ntop(AF_INET,&addr_c.sin_addr,recip,ntohs(addr_c.sin_port)));
         }
         while(num)
         {
             for (int i = 0; i < SOCK_NUM; ++i) {
                 if (socketfd[i].fd <= 0)
                     continue;
                 int len = 0;
                 bzero(recbuf, sizeof(recbuf));
                 if (socketfd[i].revents & (POLLIN | POLLERR)) {
                     if ((len = read(socketfd[i].fd, recbuf, sizeof(recbuf))) < 0) {
                         //此处出现ECONNRESET可能是客户端给服务端发送Fin,服务端回ACK前客户端就GG了,此时ACK发出,客户端端口好已经被释放
                         //客户端收到ACK发现没有对于端口号会给回复一个RST复位
                         if (errno == ECONNRESET) {
                             close(socketfd[i].fd);
                             socketfd[i].fd = -1;
                         } else {
                             //凉了
                             exit(1);
                         }
                     } else if (0 == len) {
                         //断开连接
                         close(socketfd[i].fd);
                         socketfd[i].fd = -1;
                     } else {
                         printf("%s\n", recbuf);
                         write(socketfd[i].fd, recbuf, strlen(recbuf));
                     }
                     break;
                 }

             }
            num--;

         }


    }
    close(socket_ser);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/woshichaoren1/article/details/85541001