• 【Unix网络编程】chapter6IO复用


    chapter6

    •  6.1 概述
    •   I/O复用典型使用在下列网络应用场合。
      •     (1):当客户处理多个描述符时,必须使用IO复用
      •     (2):一个客户同时处理多个套接字是可能的,不过不叫少见。
      •     (3):如果一个TCP服务器既要处理监听套接字,又要处理已连接套接字。
      •     (4):如果一个服务器既要处理TCP,又要处理UDP
      •     (5):如果一个服务器要处理多个服务或多个协议
      •     IO复用并非只限于网络,许多重要的应用程序也需要使用这项技术。
    •  6.2 I/O模型
    •   在Unix下可用的5种I/O模型的基本区别:
      •     (1)阻塞式I/O
      •     (2)非阻塞式I/O
      •     (3)I/O复用(select和poll)
      •     (4)信号驱动式I/O(SIGIO)
      •     (5)异步I/O(POSIX的aio_系列函数)
      • 6.2.1 阻塞式I/O
      • 6.2.2 非阻塞式I/O模型
      •  6.2.3 I/O复用模型
        • 有个I/O复用,我们就可以调用select或poll,阻塞在这两个系统调用中的某一个之上,而不是阻塞在真正的I/O系统调用上。
      • 6.2.4 信号驱动式I/O模型
        • 我们也可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们。我们称这种模型为信号驱动式I/O
      • 6.2.5 异步I/O模型
    •  6.3 select函数
      •   该函数允许进程指示内核等待多个事件中的任何一个发生,并且在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
      •   我们调用select告知内核对那些描述符(就读写或异常)感兴趣以及等待多长时间。
      •   #include <sys/select.h>
      •   #include <sys/time.h>
      •   int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, cosnt struct timeval *timeout);
        • maxfdp1:最大的描述符ID+1
      •   struct timeval
      •   {
        •  long tv_sec; //秒
        •  long tv_usec;//微妙
      •   };
      •   void FD_ZERO(fd_set *fdset);
      •   void FD_SET(int fd, fd_set *fdset);
      •   void FD_CLR(int fd, fd_set *fdset);
      •   int FD_ISSET(int fd, fd_set *fdset);
      • 6.3.1描述符就绪条件
        • (1):满足下列4个条件中的任何一个时,一个套接字准备好读
          • a):
          • ......
      • 6.3.2 select的最大描述符
    • 6.4 str_cli函数
    • 6.5 批量输入
    • 6.6 shutdown函数
      • 终止网络连接的方法不是调用close函数。不过close有两个限制,却可以使用shutdown来避免
      • (1):close把描述符的引用计数减1,但在该计数为0时才关闭套接字
      • (2):close终止读和写两个方向的数据传送。
        • #include <sys/socket.h>
        • int shutdown(int sockfd, int howto);
          • OK : 0 FAILED:-1
    • 6.8 TCP Service
      •  1 /* include fig01 */
         2 #include    "unp.h"
         3 
         4 int
         5 main(int argc, char **argv)
         6 {
         7     int                    i, maxi, maxfd, listenfd, connfd, sockfd;
         8     int                    nready, client[FD_SETSIZE];
         9     ssize_t                n;
        10     fd_set                rset, allset;
        11     char                buf[MAXLINE];
        12     socklen_t            clilen;
        13     struct sockaddr_in    cliaddr, servaddr;
        14 
        15     listenfd = Socket(AF_INET, SOCK_STREAM, 0);
        16 
        17     bzero(&servaddr, sizeof(servaddr));
        18     servaddr.sin_family      = AF_INET;
        19     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        20     servaddr.sin_port        = htons(SERV_PORT);
        21 
        22     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
        23 
        24     Listen(listenfd, LISTENQ);
        25 
        26     maxfd = listenfd;            /* initialize */
        27     maxi = -1;                    /* index into client[] array */
        28     for (i = 0; i < FD_SETSIZE; i++)
        29         client[i] = -1;            /* -1 indicates available entry */
        30     FD_ZERO(&allset);
        31     FD_SET(listenfd, &allset);
        32 /* end fig01 */
        33 
        34 /* include fig02 */
        35     for ( ; ; ) {
        36         rset = allset;        /* structure assignment */
        37         nready = Select(maxfd+1, &rset, NULL, NULL, NULL);
        38 
        39         if (FD_ISSET(listenfd, &rset)) {    /* new client connection */
        40             clilen = sizeof(cliaddr);
        41             connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
        42 #ifdef    NOTDEF
        43             printf("new client: %s, port %d
        ",
        44                     Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
        45                     ntohs(cliaddr.sin_port));
        46 #endif
        47 
        48             for (i = 0; i < FD_SETSIZE; i++)
        49                 if (client[i] < 0) {
        50                     client[i] = connfd;    /* save descriptor */
        51                     break;
        52                 }
        53             if (i == FD_SETSIZE)
        54                 err_quit("too many clients");
        55 
        56             FD_SET(connfd, &allset);    /* add new descriptor to set */
        57             if (connfd > maxfd)
        58                 maxfd = connfd;            /* for select */
        59             if (i > maxi)
        60                 maxi = i;                /* max index in client[] array */
        61 
        62             if (--nready <= 0)
        63                 continue;                /* no more readable descriptors */
        64         }
        65 
        66         for (i = 0; i <= maxi; i++) {    /* check all clients for data */
        67             if ( (sockfd = client[i]) < 0)
        68                 continue;
        69             if (FD_ISSET(sockfd, &rset)) {
        70                 if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
        71                         /*4connection closed by client */
        72                     Close(sockfd);
        73                     FD_CLR(sockfd, &allset);
        74                     client[i] = -1;
        75                 } else
        76                     Writen(sockfd, buf, n);
        77 
        78                 if (--nready <= 0)
        79                     break;                /* no more readable descriptors */
        80             }
        81         }
        82     }
        83 }
        84 /* end fig02 */
        View Code
    • 6.9 pselect函数
      • #include <sys/select.h>
      • #include <signal.h>
      • #include <time.h>
      • int pselect(int masfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,const struct timespec *timeout,const sigset_t *sigmask);
      • pselect相对于通常的select有两个变化
        • pselect使用timespec结构,而不使用timeval结构。
          • struct timespec{
            • time_t tv_sec;
            • long tv_nsec; // 纳秒书
          • };
        • pselect函数增加了第六个参数:一个指向信号掩码的指针。
          • ......
    • 6.10 poll函数
      • #include <poll.h>
      • int poll(struct pollfd *fdarray,unsigned long nfds, int timeout);
      • 如果有就绪描述符则返回去数目,若超时则为0,若出错则为-1
      • struct pollfd{
        • int fd;
        • short events;
        • short revents;
        • };
    作者:长风 Email:844064492@qq.com QQ群:607717453 Git:https://github.com/zhaohu19910409Dz 开源项目:https://github.com/OriginMEK/MEK 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 感谢您的阅读。如果觉得有用的就请各位大神高抬贵手“推荐一下”吧!你的精神支持是博主强大的写作动力。 如果觉得我的博客有意思,欢迎点击首页左上角的“+加关注”按钮关注我!
  • 相关阅读:
    JavaScript常用单词整理总结
    花了100多去KTV不是唱歌,竟然是……
    当你左右看看没有发现我时,千万千万别往看……
    winform分页案例简单实现方式~
    来自一位家长的肺腑之言,句句在理!!!
    “小朋友”们节日快乐呀~
    你在学校我安排了你没有做到最多凶你一顿,在公司不一样,直接得让走人!...
    你也可以做一个简易抽奖程序!
    不好意思,你这个加分理由不行……
    【RocketMQ】客户端源码解析
  • 原文地址:https://www.cnblogs.com/zhaohu/p/8939973.html
Copyright © 2020-2023  润新知