Linux网络编程IO复用

Linux网络编程IO复用,第1张

Linux网络编程IO复用 多路IO转换:

I/O多路复用使得程序能同时监听多个文件描述符能够提高程序的性能

原理:借助内核,select来监听,客户端连接、数据通信事件。

select原型:

int select (int maxfd + 1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval * timeout);

参数一:最大的文件描述符加1。
参数二:用于检查可读性,
参数三:用于检查可写性,
参数四:用于检查带外数据,
参数五:一个指向timeval结构的指针,用于决定select等待I/o的最长时间。如果为空将一直等待。t
select:

 
void FD_ZERO(fd_set*set);            ---清空一个文件描述符集合。
            fd_set rset;
            FD_ZERO(&rset);
void FD_SET(int fd, fd_set *set);        ---将一个文件描述符从监听集合 移除。
            FD_CLR(4, &rset);
int FD_ISSET(int fd,fd_set *set);        ---判断一个文件描述符是否在监听集合中。
            返回值:在:1;不在:0;
            FD_ISSET(4, &rset);

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds:监听的所有文件描述符中,最大文件描述符+1
readfds:读文件描述符监听集合。    传入、传出参数
writefds:写文件描述符监听集合。    传入、传出参数    NULL
exceptfds:异常 文件描述符监听集合   传入、传出参数   NULL
timeout:    > 0:    设置监听超时时长。
                    NULL:阻塞监听
                    0:        非阻塞监听,轮询
返回值:
                    >0:所有监听集合(3个)中,满足对应事件的总数。
                    0:    没有满足监听条件的文件描述符
                    -1:    errno

思路分析:

lfd=socket();                        创建套接字
bind();                                  绑定地址结构
listen();                                 设置监听上限
fd_set rset, allset;                创建r监听集合
FD_ZERO(&allset);                将r监听集合清空
FD_SET(lfd,&allset);                将lfd添加至读集合中。
while(1){
    rset=allset;                保存监听集合
    ret=select(lfd+1,&rset, NULL,NULL,NULL);        监听文件描述符集合对应事件。
    if(ret>0){                                     有监听的描述符满足对应事件
        if(FD_ISSET(lfd,&rset)) {                   //1在。0不在
            cfd=accept();                            建立连接,返回用于通信的文件描述符
            maxfd=cfd;
            FD_SET(cfd,&allset);                     添加到监听通信描述符集合中。
            }
            for(i=lfd+1;i<=最大文件描述符;i++){
                FD_ISSET(i,&rset)                    有read、write事件
                read()
                小--大
                write();
            }
    
        }
}

select优缺点:

缺点:监听上限受文件描述符限制。最大 1024

检测满足条件的fd,自己添加业务逻辑提高小。提高了编码难度。

优点:跨平台。win、Linux、macOS、Unix、mips

poll
poll:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
     fds:监听的文件描述符【数组】
        struct pollfd{
            int fd:              待监听的文件描述符
            short events:        待监听的文件描述符对应的监听事件
                                  取值:POLLIN、POLLOUT、POLLERR
            short revnets:        传入时,给0。如果满足对应事件的话,返回 非0---》POLLIN、POLLOUT、POLLERR
         }
    nfds:监听数组的,实际有效监听个数。
    timeout:> 0:超时时长。 单位:毫秒。
                -1:阻塞等待
                0:不阻塞
    返回值:返回满足对应监听事件的文件描述符 总个数。

优点:
    自带数组结构。将监听事件集合 和返回事件集合  分离。
    拓展  监听上限。    超出1024限制。

缺点:
    不能跨平台。Linux
    无法直接定位满足监听事件的文件描述符, 编码难度较大。

read函数
read函数返回值:
        > 0:实际读到的字节数
        = 0:socket中,表示对端关闭。close()
        -1:如果errno==EINTR     被异常终端。需要重启。
    如果errno==EAGIN或EWOULDBLOCK以非阻塞方式读数据,但是没有数据。需要,再次读。
    如果errno==EConNRESET    说明连接被  重置。需要close( ),移除监听队列。
    错误。

突破1024文件描述符限制:
        cat /proc/sys/fs/file-max  -->当前计算机能打开的最大文件个数。受硬件影响。
        ulimit -a                     ——>当前用户下的进程,默认打开文件描述符个数。缺省为1024
        修改:
                打开sudo vi /etc/security/limits.conf,写入:
                * soft nofile 65536             ——>设置默认值,可以直接借助命令修改。【注销用户,使其生效】
                * hard nofile 100000           ——>命令修改上限。

epoll
epoll:

int epoll_create(int size);                                                  创建一棵监听红黑树
     size:创建的红黑树的监听节点数量。(仅供内核参考。)
      返回值:指向新创建的红黑树的根节点的fd。
             失败:-1 errno

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);         *** 作监听红黑树
     epfd:epoll_create 函数的返回值。    epfd
      op:对该监听红黑树所做的 *** 作。
               EPOLL_CTL_ADD 添加fd到 监听红黑树
               EPOLL_CTL_MOD 修改fd在监听红黑树上的监听事件。
               EPOLL_CTL_DEL    将一个fd从监听红黑树上摘下(取消监听)
           fd:
               待监听的fd
           event:本质 struct epoll_event 结构体  地址
                成员 events:
                   EPOLLIN/EPOLLOUT/EPOLLERR
                 成员 data:联合体:
                    int fd;    对应监听事件的fd
                    void *ptr;
                    uint32_t u32;
                    uint64_t u64;
                返回值:成功 0;失败:-1 errno

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);    阻塞监听
        epfd:epoll_create 函数的返回值。  epfd
        events:传出参数,【数组】,满足监听条件的哪些fd结构体。
        maxevents:数组 元素的总个数。    1024
                struct epoll_event evnets[1024];
        timeout:
                -1:阻塞
                0: 不阻塞
                >0:超出时间(毫秒)
        返回值:
                >0:满足监听的总个数。    可以用作循环上限。
                 0:没有fd满足监听事件
                -1:失败。 errno

epoll实现多路IO转接思路

lfd=socket();            监听连接事件lfd
bind();
listen();
int epfd=epoll_create(1024);                epfd,监听红黑树的树根。
struct epoll_event    tep, ep[1024];        tep,用来设置单个fd属性,ep是epoll_wait()传出的满足监听事件的数组。
tep.events=EPOLLIN;
tep.data.fd=lfd
epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&tep);        将lfd添加到监听红黑树上。

while(1){
   ret=epoll_wait(epfd,ep,1024,-1);                        实施监听
   for(i=0;i0){
                小--大
                write(ep[i].data.fd,buf,n)
            }
         }
     }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5720934.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存