UNP学习_I/O复用之poll函数实现回射服务器

UNP学习_I/O复用之poll函数实现回射服务器

1、函数原型:

#include
struct pollfd{
	int fd;//文件描述符
	short events;//等待的事件
	short revents;//实际发生的事件
};
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
//fds: 数组地址
//nfds: 数组的最大长度,数组中最后一个元素下标+1。内核会轮询fd数组中的每个文件描述符
//timeout: -1 : 永久阻塞;  0 :调用完成立刻返回; >0等待的时长(ms)
//返回值:I/O发生变化的文件描述符的个数

2、实现代码

// File Name: poll_server.c
// Author: AlexanderGan
// Created Time: Wed 29 Jul 2020 04:31:41 PM CST

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(int argc, char* argv[]){
     if(argc < 2)
    {
        printf("eg: ./a.out IP port\n");
    }
    int port = atoi(argv[1]);

    struct sockaddr_in serv_addr, client_addr;
    socklen_t serv_len = sizeof(serv_addr);
    socklen_t cli_len = sizeof(client_addr);
    //创建套接字
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    printf("lfd = %d\n",lfd);
    //初始化服务器
    memset(&serv_addr,0,serv_len);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port);
    //绑定ip和端口
    bind(lfd,(struct sockaddr*)&serv_addr,serv_len);
    //设置同时监听的最大个数
    listen(lfd,36);
    printf("Start accept !\n");
    //poll结构体
    struct pollfd allfd[1024];
    int max_index = 0;
    //初始化
    for(int i = 0;i < 1024; i++){
        allfd[i].fd = -1;
    }
    allfd[0].fd = lfd;
    allfd[0].events = POLLIN;

    while(1)
    {
        int i = 0;
        int ret = poll(allfd,max_index+1,-1);
        if(ret == -1)
        {
            printf("poll error!\n");
            exit(1);
        }
        
        if(allfd[0].revents & POLLIN){
            int cfd = accept(lfd,(struct sockaddr*)&client_addr,&cli_len);
            printf("======start======,cfd  = %d\n",cfd);
            //cfd添加到poll数组
            for(i; i < 1024;++i){
            
                if(allfd[i].fd == -1)
                {
                    printf("i = %d\n",i);
                    allfd[i].fd = cfd;
                    break;
                }
             
            }
            allfd[i].events = POLLIN;
            //更新max_index
            max_index = max_index < i ? i : max_index;
            printf("max_index = %d\n",max_index);
        }

        //遍历数组
        for(i = 1; i <= max_index; i++){
            int fd = allfd[i].fd;
            printf("i = %d,fd = %d\n",i,fd);
            if(fd == -1) continue;
            bool res = (allfd[i].revents & POLLIN);
            printf("res = %d\n",(int)res);
            if(allfd[i].revents & POLLIN){
                printf("recv!");
                //接受数据
                char buf[1024] = {0};
                int len = recv(fd,buf,sizeof(buf),0);
                printf("len == %d\n", len);
                if(len == -1)
                {
                    perror("recv error");
                    exit(1);
                }
                else if(len == 0)
                {
                    allfd[i].fd = -1;
                    close(fd);
                    printf("客户端已主动断开连接。\n");

                }
                else
                {
                    printf("recv buf = %s\n",buf);
                    //小写全变大写
                    for(int k = 0; k < len;++k)
                    {
                        buf[k] = toupper(buf[k]);
                    }
                    printf("buf toupper = %s\n",buf);
                    send(fd,buf,strlen(buf)+1,0);
                }
            }

        }
    }
    close(lfd);
  return 0 ;
}

3、poll的优缺点

优点:
(1)可以等待多个描述符就绪。
(2)poll没有描述符数量的上限限制,因为在内核中它的遍历线性结构是基于链表来存储的。

缺点:
(1)每次调用poll,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。
(2)同时每次调用poll都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。
(3)poll不能跨平台,可移植性差。
(4)只支持水平触发。

你可能感兴趣的:(Linux网络编程)