int poll(struct pollfdfds, nfds_t nfds, int timeout);
- `fds`是一个指向`pollfd`结构体数组的指针,每个结构体代表一个要监视的文件描述符
- `nfds`指定了数组中`pollfd`结构体的数量
- `timeout`指定了等待事件发生的最长时间(毫秒),特殊值`-1`表示无限等待,`0`表示立即返回,不阻塞
`pollfd`结构体包含以下字段:
struct pollfd {
int fd; // 文件描述符
short events; // 请求的事件类型
short revents; // 实际发生的事件类型(由poll函数返回时设置)
};
其中,`events`字段可以是一个或多个以下标志的按位或组合:
- `POLLIN`:有数据可读
- `POLLOUT`:可以写数据
- `POLLERR`:发生错误
- `POLLHUP`:挂起(连接已关闭)
- `POLLNVAL`:无效的文件描述符
二、Socket Poll的工作原理
`poll`机制的核心在于其非阻塞特性
当调用`poll`函数时,它会阻塞当前线程(除非`timeout`为0),直到以下情况之一发生:
1.事件就绪:监视的文件描述符中有至少一个发生了请求的事件(如可读、可写)
2.超时:如果指定了timeout且时间已到,无论是否有事件发生,`poll`都会返回
3.错误:如果发生错误,poll会立即返回,并设置相应的错误码
对于套接字而言,`poll`能够高效地检测连接状态和数据传输情况
例如,一个服务器可以同时监听多个客户端连接,使用`poll`来检测哪些连接有新数据到达,哪些连接可以发送数据,从而实现对多个连接的并发处理,而无需为每个连接分配一个独立的线程或进程
三、Socket Poll的优势
1.高效并发:poll允许单个线程管理多个I/O流,显著提高了系统的并发处理能力,降低了资源消耗
2.灵活性:通过指定不同的events,开发者可以灵活地监控多种I/O事件,满足不同的应用需求
3.跨平台性:虽然本文聚焦于Linux,但poll机制在多数类Unix系统上都是可用的,确保了代码的移植性
4.低延迟:与传统的阻塞I/O相比,poll机制能够迅速响应I/O事件,减少了不必要的等待时间,对于实时性要求较高的应用尤为重要
四、实际应用中的使用示例
下面是一个简单的示例,展示了如何在Linux下使用`poll`机制来处理多个客户端连接:
include
include
include
include
include
include
defineMAX_CLIENTS 10
defineBUFFER_SIZE 1024
int main() {
intserver_fd,client_fd,client_sockets【MAX_CLIENTS】;
structsockaddr_in server_addr, client_addr;
socklen_tclient_addr_len =sizeof(client_addr);
struct pollfdfds【MAX_CLIENTS + 1】; // +1 for server socket
charbuffer【BUFFER_SIZE】;
int nfds = 1; // Start with server socket only
// Create server socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_fd < {
perror(Socket creation failed);
exit(EXIT_FAILURE);
}
// Bind server socket to address and port
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8080);
if(bind(server_fd, (struct sockaddr)&server_addr, sizeof(server_addr)) < 0) {
perror(Bindfailed);
close(server_fd);
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if(listen(server_fd, < {
perror(Listenfailed);
close(server_fd);
exit(EXIT_FAILURE);
}
// Initialize pollfd array
fds【0】.fd = server_fd;
fds【0】.events = POLLIN;
// Main loop
while(1) {
int ret =poll(fds, nfds, -1);
if(ret < {
perror(Pollfailed);
break;
}
for(int i = 0; i < nfds;i++){
if(fds【i】.revents & POLLIN) {
if(i == { // Server socket
client_fd =accept(server_fd,(structsockaddr )&client_addr, &client_addr_len);
if (client_fd < 0) {
perror(Accept failed);
continue;
}
// Add new client socket to pollfd array
client_sockets【nfds - 1】 = client_fd;
fds【nfds】.fd = client_fd;
fds【nfds】.events = POLLIN;
nfds++;
}else { // Client socket
int bytes_read = read(fds【i】.fd, buffer, BUFFER_SIZE - 1);
if (bytes_read < 0) {
perror(Readfailed);
close(fds【i】.fd);
// Remove client socket from pollfd array
for (int j = i; j < nfds - 1; j++) {
fds【j】 = fds【j + 1】;
}
nfds--;
i--; // Adjust loop index
} elseif (bytes_read == 0) {
// Connection closed by client
close(fds【i】.fd);
// Remove client socket from pollfd array
for (int j = i; j < nfds - 1; j++) {
fds【j】 = fds【j + 1】;
}
nfds--;
i--; // Adjust loop index
} else{
buffer【bytes_read】 = 0;
printf(Received from client %d: %s
, fds【i】.fd, buffer);
// Echo the message back to the client(simplified