【问题标题】:Disconnect and Reconnect a connected datagram socket断开并重新连接已连接的数据报套接字
【发布时间】:2010-10-29 00:32:19
【问题描述】:

我正在尝试创建一个基于数据报套接字 (UDP) 的迭代服务器。 它调用连接到它从第一个 recvfrom() 调用获得的第一个客户端(是的,我知道这不是真正的连接)。 在为该客户端提供服务后,我断开了 UDP 套接字(使用 AF_UNSPEC 调用连接) 然后我调用 recvfrom() 从下一个客户端获取第一个数据包。

现在的问题是,在循环的第二次迭代中调用 recvfrom() 返回 0。我的客户端从不发送空数据包,所以会发生什么。

这就是我正在做的事情(伪代码):

s = socket(PF_INET, SOCK_DGRAM, 0)

bind(s)

for(;;)
{
  recvfrom(s, header, &client_address)  // get first packet from client
  connect(s,client_address)  // connect to this client
  serve_client(s);
  connect(s, AF_UNSPEC); // disconnect, ready to serve next client
}

编辑:我发现我的客户端意外发送了一个空数据包的错误。 现在我的问题是如何让客户端等待获得服务,而不是向任何地方发送请求(服务器连接到另一个客户端并且不为任何其他客户端提供服务)。

【问题讨论】:

    标签: networking sockets udp posix datagram


    【解决方案1】:

    connect() 在 SOCK_DGRAM 上真的完全没有必要。

    调用connect 不会阻止您接收来自其他主机的数据包,也不会阻止您发送它们。只是不要打扰,它并没有真正的帮助。

    更正:是的,显然它确实会阻止您接收来自其他主机的数据包。但是在服务器中执行此操作有点愚蠢,因为当您连接()到一个客户端时,任何其他客户端都会被锁定。此外,您仍然需要捕捉漂浮的“谷壳”。可能有一些与 DGRAM 套接字上的 connect() 相关的竞争条件 - 如果您调用 connect 并且来自其他主机的数据包已经在缓冲区中会发生什么?

    此外,0 是 recvfrom() 的有效返回值,因为空(无数据)数据包是有效的并且可以存在(实际上,人们经常使用它们)。所以你无法检查某事是否以这种方式成功。

    很可能,队列中已经有一个零字节数据包。

    您的协议应该被设计成将错误数据报被误解的可能性降到最低;出于这个原因,我建议您不要使用空数据报,而是使用幻数。

    UDP 应用程序必须能够识别“chaff”数据包并丢弃它们;他们迟早会出现。

    【讨论】:

    • Connect 设置一个内部过滤器,当使用 send() 或 recv() 时,从该过滤器接收和发送地址。 recv(): "对于 SOCK_DGRAM 套接字,数据是从连接调用中指定的目标地址的第一个排队数据报中提取的"。
    • 你是对的,我的客户正在发送(由于错误)一个空数据包。现在我有另一个问题。应该在队列中等待服务的客户端发送它的第一个请求数据包(永远不会从服务器接收到)。然后它尝试接收响应并且recv 返回-1。如何让客户等待?
    • 您是否仍然面临这个问题(您帖子的编辑部分)还是通过删除连接解决了。
    • -1:connect 通常对 UDP 非常有用。如果您不连接,您将不会获得任何 ICMP 回复的结果。如果您不连接并使用 sendto,那么您的数据包就会进入 void 并且您永远不会听到任何回复,除非对等方碰巧收到了数据包并发送了通过的回复。但是,如果您连接时出现 IP 问题,操作系统可能会收到 ICMP 解释,并且只有您已连接时才会返回给您。
    • @NicholasWilson connect() 在要为多个客户端提供服务的服务器中不是很有用。它在只想与一方对话的客户端应用程序中相当有用。
    【解决方案2】:

    man connect:

    ... 如果启动套接字不是连接模式,则 connect() 应设置套接字的对等地址,并且不建立连接。 对于 SOCK_DGRAM 套接字,对等地址标识所有 数据报在随后的 send() 函数中发送,并且限制 后续 recv() 函数的远程发送者。如果地址 是协议的空地址,套接字的对等地址 应重置。 ...

    【讨论】:

    • 那又怎样?这以何种方式回答了我的问题?
    • 问题到底是什么?
    • 对不起,如果我不清楚。问题是为什么第二次调用 recvfrom() 返回 0。我现在发现这是我的代码中的一个错误。我现在的问题是如何让客户等待获得服务,而不是让他将数据发送到现在。
    【解决方案3】:

    只是一个更正,以防有人像我一样绊倒这个。要断开连接,需要调用 sockaddr 的 sa_family 成员设置为 AF_UNSPEC。不只是通过了 AF_UNSPEC。

    【讨论】:

      猜你喜欢
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 1970-01-01
      相关资源
      最近更新 更多