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()
来监视客户端连接和客户端数据读取事件。当客户端连接或客户端发送数据时,服务器会相应地处理这些事件。这样,服务器可以在单个线程中处理多个客户端连接,实现异步操作。