多路 I/O 复用监听 3 个套接字的数据
时间: 2023-06-11 20:08:29 浏览: 135
使用多任务处理套接字的数据传输
多路 I/O 复用可以通过 select 或者 epoll 等技术实现同时监听多个套接字的数据。以下是使用 select 监听 3 个套接字的数据的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#define PORT1 8000
#define PORT2 8001
#define PORT3 8002
int main()
{
int sockfd1, sockfd2, sockfd3, maxfd;
fd_set readfds;
struct sockaddr_in addr1, addr2, addr3;
char buffer[1024];
// create socket 1
sockfd1 = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr1, 0, sizeof(addr1));
addr1.sin_family = AF_INET;
addr1.sin_port = htons(PORT1);
addr1.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd1, (struct sockaddr *)&addr1, sizeof(addr1));
listen(sockfd1, 5);
// create socket 2
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr2, 0, sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_port = htons(PORT2);
addr2.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd2, (struct sockaddr *)&addr2, sizeof(addr2));
listen(sockfd2, 5);
// create socket 3
sockfd3 = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr3, 0, sizeof(addr3));
addr3.sin_family = AF_INET;
addr3.sin_port = htons(PORT3);
addr3.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd3, (struct sockaddr *)&addr3, sizeof(addr3));
listen(sockfd3, 5);
// set up file descriptor set
FD_ZERO(&readfds);
FD_SET(sockfd1, &readfds);
FD_SET(sockfd2, &readfds);
FD_SET(sockfd3, &readfds);
maxfd = sockfd3 + 1;
while (1) {
fd_set tmpfds = readfds;
int ret = select(maxfd, &tmpfds, NULL, NULL, NULL);
if (ret < 0) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
continue;
}
if (FD_ISSET(sockfd1, &tmpfds)) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int clientfd = accept(sockfd1, (struct sockaddr *)&client_addr, &client_len);
printf("new connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(clientfd, &readfds);
if (clientfd >= maxfd) {
maxfd = clientfd + 1;
}
}
if (FD_ISSET(sockfd2, &tmpfds)) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int clientfd = accept(sockfd2, (struct sockaddr *)&client_addr, &client_len);
printf("new connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(clientfd, &readfds);
if (clientfd >= maxfd) {
maxfd = clientfd + 1;
}
}
if (FD_ISSET(sockfd3, &tmpfds)) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int clientfd = accept(sockfd3, (struct sockaddr *)&client_addr, &client_len);
printf("new connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(clientfd, &readfds);
if (clientfd >= maxfd) {
maxfd = clientfd + 1;
}
}
for (int i = sockfd3 + 1; i < maxfd; i++) {
if (FD_ISSET(i, &tmpfds)) {
int n = recv(i, buffer, sizeof(buffer), 0);
if (n <= 0) {
close(i);
FD_CLR(i, &readfds);
printf("connection closed\n");
} else {
buffer[n] = '\0';
printf("received data from %d: %s\n", i, buffer);
}
}
}
}
close(sockfd1);
close(sockfd2);
close(sockfd3);
return 0;
}
```
这段代码同时监听了 3 个套接字,当有客户端连接时,会打印出客户端的 IP 地址和端口号。当有数据到达时,会打印出数据和对应的套接字文件描述符。当连接关闭时,会打印出连接关闭的信息。可以根据自己的需要,修改代码以满足实际需求。
阅读全文