使用C语言实现非阻塞网络I/O模型

在C语言中实现非阻塞网络I/O模型通常涉及使用套接字(sockets)编程,并设置套接字为非阻塞模式。这样,当进行读或写操作时,如果数据不可用或缓冲区已满,调用将立即返回而不是阻塞。以下是一个简单的例子,演示了如何在Linux上使用非阻塞套接字进行网络I/O:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERVER_PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    fd_set readfds;
    struct timeval tv;

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置为非阻塞模式
    if (fcntl(server_fd, F_SETFL, O_NONBLOCK) == -1) {
        perror("fcntl nonblock");
        exit(EXIT_FAILURE);
    }

    // 绑定到地址和端口
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(SERVER_PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 循环等待客户端连接
    while (1) {
        FD_ZERO(&readfds);
        FD_SET(server_fd, &readfds);

        // 设置超时时间
        tv.tv_sec = 5;
        tv.tv_usec = 0;

        // 等待可读套接字
        if (select(server_fd + 1, &readfds, NULL, NULL, &tv) == -1) {
            perror("select");
            exit(EXIT_FAILURE);
        }

        // 检查服务器套接字是否可读(有新的连接)
        if (FD_ISSET(server_fd, &readfds)) {
            if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
                if (errno != EWOULDBLOCK) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }
            } else {
                printf("Accepted new connection from %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
                // 这里可以处理新的连接,例如读取和写入数据
                close(new_socket); // 关闭连接以演示
            }
        }
    }

    // 关闭服务器套接字
    close(server_fd);

    return 0;
}

在这个例子中,我们创建了一个TCP服务器套接字,并将其设置为非阻塞模式。然后,我们绑定它到一个端口,并开始监听连接。使用select函数来等待套接字变得可读(即有新连接)。如果服务器套接字在select的超时时间内变得可读,我们使用accept函数接受新连接。如果accept调用返回-1,并且错误码是EWOULDBLOCK,这意味着没有新的连接准备好,我们可以继续等待。

请注意,这个例子仅演示了如何接受新的连接。在实际应用中,你可能还需要读写数据、关闭连接,以及处理多个并发的客户端连接。为此,你可能会想要使用多线程或事件驱动的模型(如libevent或libev)来更有效地管理多个套接字。

此外,这个例子没有处理错误情况,例如bind或listen失败。在实际应用中,你应该妥善处理所有可能的错误情况。

你可能感兴趣的:(linux,c语言)