Linux的socket编程确实支持异步操作
在Linux中,可以使用select()
、poll()
或epoll()
等系统调用来实现异步I/O。这些函数允许您监视多个文件描述符(包括套接字),以便在其中一个或多个文件描述符准备好进行I/O操作时通知您。这样,您可以在单个线程中处理多个网络连接,从而实现异步操作。
以下是一个简单的示例,说明如何使用select()
实现异步socket操作:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/select.h> #define BUF_SIZE 1024 int main() { int serv_sock, clnt_sock; struct sockaddr_in serv_addr, clnt_addr; socklen_t clnt_addr_size; fd_set readfds; int max_fd; char buf[BUF_SIZE]; // 创建套接字 if ((serv_sock = socket(PF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 配置服务器地址 memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(8080); // 绑定套接字 if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听连接 if (listen(serv_sock, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } // 初始化文件描述符集合 FD_ZERO(&readfds); max_fd = serv_sock; // 将服务器套接字添加到文件描述符集合 FD_SET(serv_sock, &readfds); while (1) { // 等待文件描述符集合中的事件 if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0) { perror("select"); exit(EXIT_FAILURE); } // 检查服务器套接字是否准备好接受连接 if (FD_ISSET(serv_sock, &readfds)) { clnt_addr_size = sizeof(clnt_addr); // 接受客户端连接 if ((clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, (socklen_t *)&clnt_addr_size)) < 0) { perror("accept"); exit(EXIT_FAILURE); } // 将客户端套接字添加到文件描述符集合 FD_SET(clnt_sock, &readfds); max_fd = max(max_fd, clnt_sock); printf("Connected client IP: %s, port: %d\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port)); } // 检查客户端套接字是否准备好读取数据 if (FD_ISSET(clnt_sock, &readfds)) { int str_len = read(clnt_sock, buf, BUF_SIZE); if (str_len <= 0) { printf("Client disconnected\n"); FD_CLR(clnt_sock, &readfds); close(clnt_sock); } else { printf("Received message from client: %s\n", buf); send(clnt_sock, "Message received", strlen("Message received"), 0); } } } // 关闭套接字 close(serv_sock); return 0; }
这个示例中的服务器使用select()
来监视客户端连接和客户端数据读取事件。当客户端连接或客户端发送数据时,服务器会相应地处理这些事件。这样,服务器可以在单个线程中处理多个客户端连接,实现异步操作。