在多个端口接收UDP数据

4

在两个端口上使用recvfrom接收数据是否可行?我有一个用于用户请求的端口和另一个用于聊天消息的端口。是否可以绑定两个不同端口的套接字,并使用一个recvfrom()接收数据?

谢谢

编辑 这段代码是否有效?

int socket_fd,socket_fd2;
struct sockaddr_in addr, chat_addr;

addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");

chat_addr.sin_family = AF_INET;
chat_addr.sin_port = htons(4321);
chat_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

bind(socket_fd2, (struct sockaddr *) &chat_addr, sizeof(struct sockaddr_in));
bind(socket_fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));

我想在两个不同的端口接收数据。

2个回答

3
不,使用单个recvfrom调用无法从两个套接字读取数据,因为该函数只接受单个套接字文件描述符参数。您需要为每个端口创建一个线程或使用机制(例如selectpoll)来确定哪些套接字有等待读取的数据。在后一种情况下,一旦知道哪些套接字有未处理数据,可以针对该特定套接字调用recvfrom以获取所需数据,例如:
// set up select parameters
fd_set socks;
FD_ZERO(&socks);
FD_SET(socket_fd, &socks);
FD_SET(socket_fd2, &socks);

// find out which sockets are read - NB: it might be both!
int nsocks = max(socket_fd, socket_fd2) + 1;
if (select(nsocks, &socks, (fd_set *)0, (fd_set *)0, 0) >= 0) {
     if (FD_ISSET(socket_fd, &socks)) {
          // handle socket 1
          recvfrom(socket_fd, ...);
     }
     if (FD_ISSET(socket_fd2, &socks)) {
          // handle socket 2
          recvfrom(socket_fd2, ...);
     }
}

注意:这只是一个简单的样例 - 真实的代码会有错误检查等功能。


所以我需要将两个套接字绑定到我的服务器并使用例如select吗? - user1324258
当使用select接收数据时,如何获取发送者地址? - user1324258
你不会通过select()函数接收数据,而是select()函数会告诉你哪个套接字已经准备好读取数据,然后你可以像往常一样使用recvfrom()函数来读取数据。 - Jeremy Friesner
那么,我需要使用recvfrom()来接收数据,而不是使用read()吗? - user1324258
@user1324258 不是的,你可以用任何一个函数,但只有在未绑定套接字上使用 recvfrom 才能获得客户端IP地址。 - Alnitak
@HUJSUNCHAI 你不能向 recvfrom 函数提供多个套接字文件描述符。 - Alnitak

2
使用select/poll方法对于UDP是正确的。
我的先前答案是错误的,因为我曾经被我的工作代码困惑了一段时间,它实际上是要使用无端口协议如ICMP和其他协议。
然而,回到UDP,这取决于你是服务器还是客户端。
当你发送UDP数据包时,通常会将正在使用的端口绑定到套接字上,或者在发送数据时自动分配一个临时端口。因此,通常稍后可以调用recvfrom()来接收回复,该回复通常会发送回绑定或分配给您套接字的端口。在这种情况下,使用UDP,您可以使用单个本地套接字和单个本地端口与两个(以及更多)不同的远程地址和端口组合进行通信-可以考虑像反向服务器这样的东西:-)
此外,根据协议和系统功能,您可以为一个端口使用两个套接字,或者为无端口协议(如ICMP)使用两个套接字-在这种情况下,每个套接字都应接收其自己收到的数据的副本。
以上只是有趣的内容,没有实际意义。
对于您来说,实际的解决方案甚至不需要上述提到的在两个套接字之间使用select/poll,而是使用一个单独的套接字,并通过内部协议设计进行分离-例如,在数据包中放入类似于通道标识符的东西,您将节省端口堆栈。

这个答案仍然是错误的。单个套接字FD无法接收发送到多个UDP端口的数据。 - Alnitak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接