• 用 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

  • 相关阅读:
    转载php在IIS中运行
    程序员必去的网站
    分享一下jQuery UI的地址
    dbcp相关配置
    shell学习第二弹-进阶
    shell学习第一弹-初识
    java servlet 3.0文件上传
    Junit使用第二弹
    各个数据库中,查询前n条记录的方法
    junit使用第一弹
  • 原文地址:https://www.cnblogs.com/ganrui/p/3704268.html
Copyright © 2020-2023  润新知