1

所以,我正在用 C 语言创建一个使用 UDP 的服务器,并且我想监听来自许多来源的传入数据包。因此,当我调用 时ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict),包含发送者信息的第 5 个参数可能会有所不同。

有没有办法在不知道每个客户地址信息的情况下接收数据包?而且,这对 C 的库有可能吗?

这是我的代码:

int file_descriptor;
char data[1024];
int bytes_recved;
sockaddr_in iDontKnow;
socklen_t addr_len = sizeof(iDontKnow);
if ((bytes_recved = recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)) < 0) {
    perror("Failed to receive data");
}

我注意到当使用 Java 的 DatagramSocket 和 DatagramPacket 类接收数据时,DatagramSocket 的receive函数接受了一个 DatagramPacket 类型的参数。然而,这个 DatagramPacket 只保存放置数据的对象。那么,为什么 C 实现 UDP 接收需要知道发送者的信息呢?

4

4 回答 4

5

有没有办法在不知道每个客户地址信息的情况下接收数据包?

好吧,无论如何,您不需要事先知道发件人信息。收到数据包后,发送方信息(如果可用)将存储到address.

手册页

ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
                   int flags, struct sockaddr *restrict address,
                   socklen_t *restrict address_len);

[...]如果地址参数不是空指针并且协议提供消息的源地址,则接收消息的源地址应存储在sockaddr地址参数指向的结构中,并且该地址的长度应存储在address_len参数指向的对象中。

关于为什么部分,在无连接套接字的情况下,除非您知道通信中数据包的发送者地址,否则您无法回复或响应发送者。因此,需要在无连接模式下专门了解发送者信息recvfrom(),然后连同接收到的数据一起为我们提供有关发送者的信息。


编辑:

在您的代码中

recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)

是错误的,就像strlen(data)UB 一样,因为您试图计算未初始化的 char 数组的长度,该数组不符合string的条件。它调用未定义的行为。您可能想使用sizeof(data), 作为data一个数组。

如果您对发件人的信息不感兴趣,只需传递 aNULL作为相应的参数。


除此之外,对于无连接套接字 (UDP),实际上需要获取发送者信息。对于面向连接的套接字,您有另一个精简的替代方案,recv()它只负责接收和存储数据。

于 2017-03-01T06:08:24.280 回答
1

但是,这DatagramPacket仅包含放置数据的对象。

以及源地址和端口,以及数据的长度。

那么,为什么 C 实现 UDP 接收需要知道发送者的信息呢?

它没有。它可以选择告诉源地址和端口。这是一个结果参数,而不是输入。

于 2017-03-01T06:43:45.960 回答
1

您比较了 Java 和 C 中的不同函数。在 C 中还有一个recv()函数不提供任何地址。recvfromover的唯一目的recv是获取发件人的地址。通常,服务器会回复他们收到的数据包。没有一个不可能的地址。

如果您不关心数据包的发件人,请使用recv.

recvfrom或者反过来说:如果你不关心发件人,你为什么选择recv?

我想知道如果服务器服务器不关心客户端的地址,它会做什么......但这与您的问题无关。

于 2017-03-01T07:09:01.417 回答
-2

你可以这样做,

int sockfd_recv;
struct sockaddr_in recvaddr;
bzero(&recvaddr, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(port_recv);
recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sockfd_recv, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
于 2017-03-01T06:22:14.313 回答