IO多路复用:select

注:为了方便管理socket,使用了std::set数据结构。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <set>

#define BUF_SIZE 1024
#define SERVER_PORT 10001

int main(int argc, char *argv[])
{
    char buf[BUF_SIZE];  // 缓冲区

    // 新建Socket
    // AF_INET:IP协议族
    int listenFd = socket(AF_INET, SOCK_STREAM, 0);

    // 设置服务器地址
    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 将Socket绑定到上述地址
    bind(listenFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));   
    listen(listenFd, 100);  // 开始接受连接

    // 用于保存客户端连接生成的Socket的fd
    std::set<int> clientFds;

    int maxFd = listenFd;  // 表示当前所有fd的最大值

    fd_set allSet;  // 用于保存当前所有fd
    FD_ZERO(&allSet);
    FD_SET(listenFd, &allSet);

    for (;;)
    {
        fd_set readSet = allSet;  // 用来传给内核的fd_set,之所以拷贝一份是因为内核会修改它
        int nready = select(maxFd + 1, &readSet, NULL, NULL, NULL);

        // 检查是否有客户端新建连接
        if (FD_ISSET(listenFd, &readSet))
        {
            // 获取客户端连接生成的Socket
            struct sockaddr_in clientAddr;
            socklen_t clientLen = sizeof (clientAddr);
            int connFd = accept(listenFd, (struct sockaddr*)&clientAddr, &clientLen);

            printf("Socket %d created\n", connFd);
            fflush(stdout);

            // 将客户端连接生成的Socket的fd保存起来
            clientFds.insert(connFd);

            // 将客户端连接生成的Socket的fd加入select中
            FD_SET(connFd, &allSet);

            if (connFd > maxFd) maxFd = connFd;

            nready -= 1;
            if (nready <= 0) continue;
        }

        // 检查是否存在客户端Socket有数据需要读
        for (int sockFd : clientFds)
        {
            if (FD_ISSET(sockFd, &readSet))
            {
                int n = read(sockFd, buf, BUF_SIZE);
                if (n == 0)
                {
                    close(sockFd);  // 关闭fd
                    FD_CLR(sockFd, &allSet);
                    clientFds.erase(sockFd);
                    printf("Socket %d closed\n", sockFd);
                    fflush(stdout);
                }
                else
                {
                    buf[n] = '\0';
                    write(sockFd, buf, n);
                    printf("Socket %d said : %s\n", sockFd, buf);
                    fflush(stdout);
                }
                nready -= 1;
                if (nready <= 0) break;
            }
        }
    }

    return 0;
}
使用 Hugo 构建
主题 StackJimmy 设计