• 用 select 实现处理多连接的异步通讯服务器


    因为对于任何句柄 ( file descriptor ) select 函数都能检测出其状态变化,对于用于 listen 的 socket 也是一样。

    只要把用于 listen 的 socket 加入 ( FD_SET ) 到 select 检测的集合里,当有连接到来时 select 就能判断到。因为 select 函数能处理的是句柄集合,所以加入这样一个 socket 并不与 select 判断其它 socket 的状态有任何冲突。

    • 实现片段代码:

    #define MAX_NUM_ONLINE_SOCKET 100

    int lsn_sock_fd;

    int client_sock_fd[MAX_NUM_ONLINE_SOCKET];

    fd_set rdfds;

    int maxfds;

    int tmp_fd;

    struct time tv;

    int retval;

    int i;

    maxfds = -1;

    for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) client_sock_fd[i] = -1;

    lsn_sock_fd = socket(AF_INET, SOCK_STREAM, 0);

    /* 设置监听的地址和端口 */

    /* 调用 bind 把地址信息与 socket 绑定到一起 */

    listen(lsn_sock_fd, 2);

    while(1) {

        maxfds = 0;

        FD_ZERO(&rdfds);

        if(lsn_sock_fd > 0) {

            FD_SET(lsn_sock_fd, &rdfds); /* 在这里把用于 listen 的 socket 加入到 select 判断的句柄集合里来 */

            if( lsn_sock_fd > maxfds) maxfds = lsn_sock_fd;

        }
        for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {

            if(client_sock_fd[i] > 0) {

              FD_SET(client_sock_fd[i], &rdfds); /* 把所有在线客户端连接加入到 select 检测的集合中来 */

          if( client_sock_fd[i] > maxfds) maxfds = client_sock_fd[i];

            }

        }

        tv.tv_sec = 1;

        tv.tv_usec = 0;

        if(maxfds < 1) continue;

        retval = select(maxfds + 1, &rfds, NULL, NULL, &tv);
        if(retval < 0) {

            printf("select 出错,错误编号:%d,错误信息:%s ", errno, strerror(errno));

            break;

        }

        else if(!retval) continue; /* listen 的 socket 上没有任何连接到来,在线的所有连接上也没有任何一个上有数据到来 */

        if(FD_ISSET(lsn_sock_fd, &rdfds)) { /* 说明 listen 的 socket 上有新的连接到来了 */

            tmp_fd = accept(lsn_sock_fd, ......);

            for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {

                if(client_sock_fd[i] < 0) {

                    client_sock_fd[i] = tmp_fd;

                    break;

    }

            }

             if(i == MAX_NUM_ONLINE_SOCKET) {

                    printf("连接太多了,我最多只能接受%d个连接同时在线 ", MAX_NUM_ONLINE_SOCKET);  

                    close(tmp_fd);

             }
        }
        for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {

            if(FD_ISSET(client_sock_fd[i], &rdfds)) { /* 说明第 i 个客户端连接上有数据到来了 */

                 recv(client_sock_fd[i], ......);
                 /* 对这个连接进行其它操作 */
                 send(client_sock_fd[i], ......);

                 /* 如果这个连接处理完毕了就要 close 它,并执行 client_sock_fd[i] = -1 ; */
            }

    }

    }

    From:http://hi.baidu.com/beibeiboo/item/3b6e0ecb7e6d0f50ac00ef7a

  • 相关阅读:
    webpack 热加载特别慢
    服务中台 镜像校验 格式 socp1.io:3000/ypt/ypt:12aaa_1 正则 /^([az09\.\:]+)\.([az]+)\:([az09]+)\/([az09\.]+)\/([az09_.:]+)$/
    Vue报错:Vue ERROR TypeError: Cannot read property “upgrade” of undefined
    antd 使用form表单校验 默认值问题 以及 关闭弹窗组件后再次打开里面还有上次的值
    Unable to resolve module `@babel/runtime/helpers/objectSpread`
    网易公开课(数学微课帮)初中数学教学视频学习进度
    【noi2019集训题1】 脑部进食 期望dp+高斯消元
    【xsy1300】 原题的旅行 最短路+倍增
    【xsy2978】Product of Roots 生成函数+多项式ln+多项式exp
    【NOI2019集训题2】 序列 后缀树+splay+dfs序
  • 原文地址:https://www.cnblogs.com/ganrui/p/3704268.html
Copyright © 2020-2023  润新知