linux下非阻塞模式网络通讯模型示例分享


在Linux下实现非阻塞模式网络通讯,主要涉及到将套接字(socket)设置为非阻塞状态,并通过轮询或者事件通知机制来处理网络通信。以下是一个简化的非阻塞模式网络通信模型的示例代码,以及该模型的基本说明。

### 非阻塞模式网络通信模型示例

非阻塞模式网络通信通常涉及到以下几个步骤:

1. **创建套接字**:使用`socket()`函数创建一个新的套接字。

2. **设置套接字为非阻塞模式**:通过`fcntl()`或`ioctl()`等函数将套接字设置为非阻塞模式。

3. **连接服务器**(如果是客户端):使用`connect()`函数尝试连接服务器,注意在非阻塞模式下,`connect()`可能立即返回并指示操作正在进行中(EINPROGRESS)。

4. **使用非阻塞IO操作**:通过`send()`, `recv()`, `accept()`等函数进行网络通信,这些函数在非阻塞模式下会立即返回,即使操作尚未完成。

5. **处理非阻塞IO的返回值**:根据函数的返回值和`errno`来判断操作是否成功,或者是否应该稍后重试。

6. **关闭套接字**:通信结束后,使用`close()`函数关闭套接字。

### 示例代码(简化)

以下是一个简化的非阻塞客户端示例,用于展示如何设置套接字为非阻塞模式,并尝试连接服务器。请注意,这只是一个非常基础的示例,实际应用中可能需要更复杂的错误处理和数据处理逻辑。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    int sockfd;
    struct sockaddr_in servaddr;

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

    // 设置套接字为非阻塞模式
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl failed");
        exit(EXIT_FAILURE);
    }
    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl failed");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址和端口
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(12345); // 假设服务器在12345端口
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    // 尝试连接服务器(注意:在非阻塞模式下,connect可能会立即返回)
    if (connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        if (errno != EINPROGRESS) {
            perror("connect failed");
            exit(EXIT_FAILURE);
        }
        // 在这里,你可以使用select()、poll()或epoll()来等待连接完成
        // 这里为了简化,我们省略了这部分代码
    }

    // 假设连接已经成功,现在可以进行数据的发送和接收(使用send()和recv())
    // ...

    // 关闭套接字
    close(sockfd);
    return 0;
}

### 注意

- 上述代码中的`connect()`调用在非阻塞模式下可能会立即返回`EINPROGRESS`,表示连接正在进行中。在实际应用中,你需要使用`select()`, `poll()`, 或`epoll()`等函数来等待连接完成。

- 示例代码省略了详细的错误处理和数据处理逻辑,以便专注于展示如何设置套接字为非阻塞模式。

- 非阻塞IO模型要求程序员自己管理IO操作的完成,这通常涉及到复杂的轮询或事件通知机制。在实际应用中,你可能需要考虑使用更高级的IO模型,如IO复用(select/poll/epoll)或异步IO。