繁体   English   中英

系统中的两个不同的 UDP 套接字可以绑定同一个端口吗?

[英]Can two different UDP socket in a system bind same port?

我有一个使用 UDP 连接的应用程序,现在当我尝试多次运行该应用程序时,它向我抛出异常

java.net.BindException: Address already in use: Cannot bind

但是在我的另一个使用 tcp 连接的应用程序中,我可以打开同一个应用程序的两个实例并且它工作正常。 为什么此错误仅与 UDP 连接有关?

编辑:

TCP socket:

Socket clientSocket= new Socket(ipAddress, 8000);
Socket clientSocket1= new Socket(ipAddress, 8000);

如果我像上面那样创建 TCP 套接字,使用相同的端口,它不会抛出任何错误。 但是如果我用 UDP Socket 来做这件事,它会抛出一个异常,为什么?

它与 TCP 和 UDP 之间的区别有关。 当您创建 TCP 套接字时,您正在创建到另一台机器上的端口的同步客户端连接,并且当您连接到一个地址时,您实际上也在套接字上获得了一个本地端口。 因此,在您的示例代码中,创建的两个套接字可能是

clientSocket = localhost:2649 <-> ipAddress:8000
clientSocket1 = localhost:2650 <-> ipAddress:8000

请注意,虽然它们的远程地址相同,但本地地址具有不同的端口,这就是允许的原因。 所以在这里本地和远程机器可以使用已建立的端口可靠地来回发送数据。

对于 UDP,情况并非如此(我假设您使用的是 DatagramSocket)。 由于 UDP 是异步的(而不是像 TCP 那样的同步),为了接收数据,您不会创建到另一台特定机器的绑定,例如,如果您要尝试

DatagramSocket udp1 = new DatagramSocket(8000); // = localhost:8000 <-> ?
DatagramSocket udp2 = new DatagramSocket(8000); // = localhost:8000 <-> ?

udp 套接字不知道数据来自哪里,因此不能像 TCP那样有唯一的映射,而且与 TCP 不同的是,您指定的端口是您机器的端口,而不是远程机器端口

当您创建 UDP 套接字时,另一种思考方式就像创建一个 TCP 服务器套接字。 当您创建 TCP 服务器套接字时,它正在等待来自某台机器的连接,但该机器未知,当您创建 TCP 服务器套接字时,您指定的端口是本地端口:

ServerSocket ss1 = new ServerSocket(8000); // = localhost:8000 <-> ?
ServerSocket ss2 = new ServerSocket(8000); // = localhost:8000 <-> ?

再次像 UDP 一样,这将创建绑定异常,因为端口用于本地机器并且映射不再唯一。 但是,当您接受服务器套接字上的连接时,远程机器会发挥作用以使套接字唯一,就像您创建到远程机器的 Socket 一样:

Socket s1 = ss1.accept();// localhost:8000 <-> remoteIp1:12345
Socket s2 = ss1.accept();// localhost:8000 <-> remoteIp2:54321

请注意,虽然本地地址相同,但套接字的远程地址不同,因此总映射 (localip:port<->remoteip:port) 现在是唯一的。

因此,在某种程度上,您可以将 UDP 套接字视为有点像 TCP 服务器套接字,这就是您必须将其绑定到唯一端口的原因。

您确定 TCP 应用程序确实使用非零端口号进行绑定吗? 它也不应该适用于 TCP。 端口号的目的是确定将流量路由到哪个正在运行的应用程序实例; 如果两个应用程序分别将两个套接字绑定到同一个端口号,那么路由就变得不可能,这就是错误的原因。

您必须将套接字设置为可共享的,或称为 SO_REUSEPORT。

在 C 或 C++ 中,这是通过 setsockopt 函数完成的。 当你绑定到一个端口,然后设置SO_REUSEPORT,另一个进程也可以绑定一个socket到同一个端口号。 一个例子是多进程应用程序,使用多个 CPU 内核尽可能快地读取传入的数据。 完成此操作后,流量在进程之间进行负载平衡,或者更有可能的是,第一个读取数据的人获取它(使用 UDP)。

对于 TCP,这仅与进入的新连接相关。当新连接进入时,第一个接受()连接的进程拥有该连接,但端口号仍由绑定到它的所有进程共享,并且新的随后将连接移交给第一个使用 accept() 获取它的人。 从 TCP 套接字共享 READING 是没有意义的(尽管多线程应用程序可以这样做),因为数据是作为没​​有记录分隔符的流传入的,所以让多个读者读取它只是,好,一个类比,多人阅读同一本书并在阅读时撕掉书页。 你会留下每个读者都有一个语无伦次的混乱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM