要实现C++单线程同时监听多个端口,可以使用select和poll这两个系统调用。这两个函数都可以用来完成IO多路复用,允许开发者同时监视多个文件描述符的状态。以下是实现方法的详细攻略:
1. 创建套接字
在开始监听端口之前,需要先创建套接字。使用socket函数可以创建一个套接字,其中参数domain设置为AF_INET(IPv4地址族),type设置为SOCK_STREAM(面向连接的套接字),protocol设置为0。
int sock = socket(AF_INET, SOCK_STREAM, 0);
2. 绑定端口
创建套接字后,需要将其绑定到指定的端口上。使用bind函数可以将套接字绑定到本地IP地址和端口号上。需要填写sockaddr_in结构体,其中sin_family设置为AF_INET,sin_addr.s_addr设置为INADDR_ANY(表示所有IP地址),sin_port设置为要绑定的端口号。
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
int ret = bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
3. 监听端口
绑定端口后,套接字就已经准备好监听连接请求了。使用listen函数可以将套接字转换为监听状态,并指定可以同时接受的最大连接请求数。
int backlog = 20;
int ret = listen(sock, backlog);
if (ret == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
4. 设置文件描述符集合
C++单线程同时监听多个端口需要用到select或poll函数。在使用这些函数前,需要先设置文件描述符集合。使用fd_set类型结构体表示文件描述符集合,可以使用宏FD_ZERO和FD_SET分别来初始化和添加文件描述符。
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock1, &fds);
FD_SET(sock2, &fds);
5. 调用select或poll函数
设置文件描述符集合后,可以调用select或poll函数来监听文件描述符的状态。这些函数均具有超时功能,可以使用NULL表示阻塞直到有事件发生,或使用timeval类型结构体指定超时时间。
使用select函数
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
int ret = select(1, &fds, NULL, NULL, &tv);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else {
if (FD_ISSET(sock1, &fds)) {
// 处理sock1
}
if (FD_ISSET(sock2, &fds)) {
// 处理sock2
}
}
使用poll函数
int timeout = 10000;
int ret = poll(fds, 2, timeout);
if (ret == -1) {
perror("poll");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else {
if (fds[0].revents & POLLIN) {
// 处理sock1
}
if (fds[1].revents & POLLIN) {
// 处理sock2
}
}
示例说明
示例1
使用select函数同时监听两个端口。一个端口用于接收TCP连接请求,另一个端口用于接收UDP数据包。
fd_set fds;
FD_ZERO(&fds);
FD_SET(tcp_sock, &fds);
FD_SET(udp_sock, &fds);
struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;
int ret = select(2, &fds, NULL, NULL, &timeout);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else {
if (FD_ISSET(tcp_sock, &fds)) {
printf("tcp connection request\n");
// 处理TCP连接请求
}
if (FD_ISSET(udp_sock, &fds)) {
printf("udp data received\n");
// 处理UDP数据包
}
}
示例2
使用poll函数同时监听三个端口,其中一个端口用于接收GPIO信号。当GPIO输出电平变化时,会产生电平变化中断,这时需要通过该端口接受信号并执行相应操作。
struct pollfd fds[3];
fds[0].fd = tcp_sock;
fds[0].events = POLLIN;
fds[1].fd = udp_sock;
fds[1].events = POLLIN;
fds[2].fd = gpio_sock;
fds[2].events = POLLIN;
int timeout = 10000;
int ret = poll(fds, 3, timeout);
if (ret == -1) {
perror("poll");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else {
if (fds[0].revents & POLLIN) {
printf("tcp connection request\n");
// 处理TCP连接请求
}
if (fds[1].revents & POLLIN) {
printf("udp data received\n");
// 处理UDP数据包
}
if (fds[2].revents & POLLIN) {
printf("GPIO signal received\n");
// 处理GPIO信号
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++ 单线程实现同时监听多个端口 - Python技术站