Linux UDP套接字/端口重用

时间:2014-01-17 06:09:45

标签: c linux multithreading sockets udp

我正在尝试使用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 socket编程的新手):

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

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

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

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

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

  6. 提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

  

我需要在两个插座之间进行任何锁定,还是需要处理   在操作系统?也就是说,我可以同时向两个套接字发送数据   没有得到一些奇怪的碰撞,因为两者都使用相同的端口?

对于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()。这样就可以使用单个线程完成我想要的所有操作,这样我就可以避免所有非确定性和潜在的竞争条件以及多次出现的死锁线程)

  

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

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