Introduction to linux c select server source code

 Look directly at the part of the while loop in the calling main function

Each call to select will change the value of FD_SET, so two variables, allset, and one rset are required

First, see if there is a client requesting a connection, and if there is a connection to be processed.

Here we use a newly opened array to maintain file descriptors. The advantage of this is that if a dynamic array is used, file descriptors can be dynamically maintained.

Traverse the entire client array, and then see if there is any information that can be read

The disadvantage of the select function is that FD_SET is copied to the kernel area every time, which is IO multiplexing based on the polling mechanism.

while (1) {   
        rset = allset;                                          /* 每次循环时都从新设置select监控信号集 */
        nready = select(maxfd+1, &rset, NULL, NULL, NULL);
        if (nready < 0)
            perr_exit("select error");
 
        if (FD_ISSET(listenfd, &rset)) {                        /* 说明有新的客户端链接请求 */
 
            clie_addr_len = sizeof(clie_addr);
            connfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len);       /* Accept 不会阻塞 */
            printf("received from %s at PORT %d\n",
                    inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
                    ntohs(clie_addr.sin_port));
 
            for (i = 0; i < FD_SETSIZE; i++)
                if (client[i] < 0) {                            /* 找client[]中没有使用的位置 */
                    client[i] = connfd;                         /* 保存accept返回的文件描述符到client[]里 */
                    break;
                }
 
            if (i == FD_SETSIZE) {                              /* 达到select能监控的文件个数上限 1024 */
                fputs("too many clients\n", stderr);
                exit(1);
            }
 
            FD_SET(connfd, &allset);                            /* 向监控文件描述符集合allset添加新的文件描述符connfd */
            if (connfd > maxfd)
                maxfd = connfd;                                 /* select第一个参数需要 */
 
            if (i > maxi)
                maxi = i;                                       /* 保证maxi存的总是client[]最后一个元素下标 */
 
            if (--nready == 0)
                continue;
        } 
 
        for (i = 0; i <= maxi; i++) {                               /* 检测哪个clients 有数据就绪 */
 
            if ((sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset)) {
 
                if ((n = Read(sockfd, buf, sizeof(buf))) == 0) {    /* 当client关闭链接时,服务器端也关闭对应链接 */
                    Close(sockfd);
                    FD_CLR(sockfd, &allset);                        /* 解除select对此文件描述符的监控 */
                    client[i] = -1;
                } else if (n > 0) {
                    for (j = 0; j < n; j++)
                        buf[j] = toupper(buf[j]);
                    Write(sockfd, buf, n);
                    Write(STDOUT_FILENO, buf, n);
                }
                if (--nready == 0)
                    break;                                          /* 跳出for, 但还在while中 */
            }
        }
    }

 

 

Guess you like

Origin blog.csdn.net/whatday/article/details/114257005