【问题标题】:Why does recvfrom care about who the data comes from为什么 recvfrom 关心数据来自谁
【发布时间】:2017-03-01 06:03:34
【问题描述】:

所以,我正在用 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 接收需要知道发送者的信息呢?

【问题讨论】:

  • 您显示的代码在不知道单个客户端地址信息的情况下接收数据包!你的代码不需要知道发件人的信息(你永远不会用任何东西填充iDontKnow),它就可以正常工作。

标签: c sockets network-programming udp recvfrom


【解决方案1】:

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

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

来自man page

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参数指向的对象中。

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


编辑:

在您的代码中

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

是错误的,因为strlen(data) 是 UB,因为您正在尝试计算未初始化的 char 数组的长度,该数组不符合 string 的条件。它调用undefined behavior。您可能想使用sizeof(data),因为data 是一个数组。

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


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

【讨论】:

  • 谢谢您,非常感谢您的帮助!
  • 哪个“对应”的论点?
  • @JeromeCarter 我的意思是,将(struct sockaddr*)&amp;iDontKnow, 替换为NULL,仅此而已。
  • @Gerhardh Connect,但是对于 TCP,您不需要知道发送者的信息,这就是建立连接的全部部分,不是吗?
  • @Gerhardh 如果你是服务器,你必须知道在哪里回复,这是唯一可用的机制。
【解决方案2】:

然而,这个DatagramPacket 只保存了放置数据的对象。

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

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

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

【讨论】:

  • 感谢您的反馈!
【解决方案3】:

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

如果您不关心数据包的发送者,请使用recv

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

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

【讨论】:

    【解决方案4】:

    你可以这样做,

    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));
    

    【讨论】:

    • 建议您解释原因。
    • 以及仅提供备用代码如何回答所提出的问题。
    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 2012-09-07
    • 2013-10-15
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    相关资源
    最近更新 更多