【问题标题】:Linux UDP Socket/Port ReuseLinux UDP 套接字/端口重用
【发布时间】:2014-02-06 09:05:22
【问题描述】:

我正在试验 Linux UDP 套接字。我有一台服务器和客户端以下列方式相互通信。

服务器:在端口 X 上向其子网中的所有 IP 发送广播通告。

客户端:通过将单播消息发送回服务器来响应公告。此消息将直接发送回端口 X。

在服务器上,我有一个线程定期发送通知。我现在想添加更多代码来接收来自客户端的响应以及向特定客户端发送单播消息。下面列出了我为服务器提出的方案。

线程 1

  • socket_a 上的广播,使用 setsockopt() 设置 SO_BROADCAST。在端口 X 上发送广播通知。

线程 2

  • 使用 socket_b 从端口 X 读取数据。由于代码当前结构的限制,该线程无法访问 socket_a。请注意,该端口与 socket_a 共享。调用 bind() 以读取此套接字上的数据。

线程 3

  • 使用端口 X 上的 socket_b 将单播数据发送到特定客户端。请注意,套接字和端口都与线程 2 共享,并且端口在所有三个线程和两个套接字中是通用的。

不分先后,以下是我的问题(请耐心等待,我对 unix 套接字编程还很陌生):

  1. 我需要在两个套接字之间进行任何锁定还是在操作系统中处理?也就是说,我可以同时向两个套接字发送数据并且不会因为两者使用相同的端口而发生一些奇怪的冲突吗?

  2. 我是否需要担心线程 2 接收由任一“发送者”线程发出的数据?如何防止这种情况发生?

  3. 是否需要启用任何选项才能使其正常工作?广播套接字 (socket_a) 是否在单播 (socket_b) 之前设置好?

  4. 我应该在端口 X 上创建一个专用的“接收”套接字吗?也就是说,拥有一个仅用于接收数据的套接字是否有意义?这是唯一会调用 bind() 的套接字。

  5. 鉴于所有三个线程都使用同一个端口,我还应该担心其他问题吗?不幸的是,这是我正在处理的一个约束。如果上述方案不可行,我可能不得不重新审视我的单端口设计。

提前感谢您的帮助。

【问题讨论】:

    标签: c linux multithreading sockets udp


    【解决方案1】:

    我认为这行不通。 当您将 UDP 套接字多次绑定到同一个 ip+port 时,发往该 ip+port 的数据包将被传递到任何套接字。因此,从对等方到您的 ip+port 的单播回复可能会传送到三个套接字中的任何一个。当锁定这样一个数据包时,这种行为是非常合乎逻辑的:从操作系统的角度来看,udp 数据包包含一个源 ip+port 和一个目标 ip+port。而且因为您所有的套接字都只是绑定到目标 ip+port 而已,因此任何套接字都可能在最后得到回复。

    因此,您可能需要围绕单个套接字重构您的应用程序,该套接字将用于单播和广播,并将接收所有回复并处理它们。如果您坚持使用多个线程,您可以使用同一个套接字从所有线程发送而无需锁定,但您应该只在一个线程中接收。在这个线程中,您需要确定数据包的类型,然后您可以将其“交给”正确的线程。

    【讨论】:

      【解决方案2】:

      我是否需要在两个套接字之间进行任何锁定,或者是否已处理 在操作系统中?也就是说,我可以同时向两个套接字发送数据吗? 因为两者都使用相同的端口,所以不会发生一些奇怪的冲突?

      对于 UDP,不需要锁定。也就是说,您可能仍然会发现为每个线程简单地创建一个单独的套接字更容易,这只是因为安全地协调关闭和销毁正在被多个线程使用的套接字可能有点棘手。

      我是否需要担心线程 2 接收由 “发件人”线程中的任何一个?如何防止这种情况发生?

      是的,线程 2 可能至少会看到广播数据包,也可能会看到单播数据包(如果它们曾经被发送到运行线程 2 的计算机)。避免这种情况的最简单方法是在不同的端口上进行侦听(例如,将您的广播数据包发送到端口 X,但让客户端将其单播回复数据包发送回端口 X+1;这样您在端口 X 上收到的任何数据包+1 几乎可以肯定是来自客户的单播回复)

      是否需要启用任何选项才能使其正常工作?

      只有 SO_BROADCAST 一个,AFAIK。 (如果你想让同一台机器上的多个套接字监听同一个端口,你还需要做 SO_REUSEADDR 和 [在 MacOS/X 下] SO_REUSEPORT,但希望你不需要)

      广播套接字 (socket_a) 是否在 单播一个(socket_b)?

      不,顺序无关紧要。

      我应该在端口 X 上创建一个专用的“接收”套接字吗?也就是说,会 拥有一个仅用于接收数据的套接字有意义吗? 这是唯一会调用 bind() 的套接字。

      您可以这样做,但使用相同的套接字发送和接收也可以。 (请注意,如果您使用阻塞 I/O,则必须注意诸如 recv() 之类的事情很长时间没有返回,这可能会阻止您的线程同时执行其他操作,例如发送 - 这就是为什么我几乎总是在我的程序中使用非阻塞 I/O 和 select()。这样就可以使用单个线程来做我想做的所有事情,这使我可以避免所有不确定性和潜在的竞争条件以及多个线程带来的死锁线程)

      考虑到所有这些,我还有其他问题需要担心吗? 三个线程使用同一个端口?不幸的是,这是一个 我正在使用的约束。如果上述方案是不可能的, 我可能不得不重新审视我的单端口设计。

      使用单个端口即可,只需准备好在其上接收您自己的广播数据包(即,发生这种情况时不要进入反馈循环)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-09
        • 1970-01-01
        • 2011-07-25
        • 2012-09-04
        相关资源
        最近更新 更多