Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 系统中的两个不同UDP套接字可以绑定同一端口吗?_Java_Sockets - Fatal编程技术网

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

Java 系统中的两个不同UDP套接字可以绑定同一端口吗?,java,sockets,Java,Sockets,我有一个使用UDP连接的应用程序,现在当我尝试多次运行该应用程序时,它会向我抛出一个异常 java.net.BindException: Address already in use: Cannot bind 但在我的另一个应用程序中,它使用tcp连接,我可以打开同一个应用程序的两个实例,并且工作正常。为什么只有UDP连接才会出现此错误 编辑: 如果我像上面那样创建TCP套接字,使用相同的端口,它不会抛出任何错误。但是如果我使用UDP套接字执行此操作,它会引发异常,为什么?您确定TCP应用程序

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

java.net.BindException: Address already in use: Cannot bind
但在我的另一个应用程序中,它使用tcp连接,我可以打开同一个应用程序的两个实例,并且工作正常。为什么只有UDP连接才会出现此错误

编辑:


如果我像上面那样创建TCP套接字,使用相同的端口,它不会抛出任何错误。但是如果我使用UDP套接字执行此操作,它会引发异常,为什么?

您确定TCP应用程序确实使用非零端口号进行绑定吗?它也不应该适用于TCP。端口号的目的是识别将流量路由到哪个正在运行的应用程序实例;如果两个应用程序分别将两个套接字绑定到同一端口号,则无法进行路由,这就是为什么会出现错误。

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

clientSocket = localhost:2649 <-> ipAddress:8000
clientSocket1 = localhost:2650 <-> ipAddress:8000
clientSocket=localhost:2649 IP地址:8000
clientSocket1=localhost:2650 IP地址:8000
请注意,虽然它们的远程地址相同,但本地地址具有不同的端口,这就是允许这样做的原因。因此,本地计算机和远程计算机可以使用已建立的端口可靠地来回发送数据

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

DatagramSocket udp1 = new DatagramSocket(8000); // = localhost:8000 <-> ?
DatagramSocket udp2 = new DatagramSocket(8000); // = localhost:8000 <-> ?
DatagramSocket udp1=新的DatagramSocket(8000);//=本地主机:8000?
DatagramSocket udp2=新DatagramSocket(8000);//=本地主机:8000?
udp套接字不知道数据来自何处,因此不能有像TCP这样的唯一映射,也与TCP不同,您指定的端口是您机器的端口,而不是远程机器端口

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

ServerSocket ss1 = new ServerSocket(8000); // = localhost:8000 <-> ?
ServerSocket ss2 = new ServerSocket(8000); // = localhost:8000 <-> ?
ServerSocket ss1=新的ServerSocket(8000);//=本地主机:8000?
ServerSocket ss2=新的ServerSocket(8000);//=本地主机:8000?
同样,与UDP类似,这将创建绑定异常,因为端口用于本地计算机,并且映射不再是唯一的。但是,当您接受服务器套接字上的连接时,远程机器将发挥作用,使套接字唯一,就像您创建远程机器的套接字一样:

Socket s1 = ss1.accept();// localhost:8000 <-> remoteIp1:12345
Socket s2 = ss1.accept();// localhost:8000 <-> remoteIp2:54321
Socket s1=ss1.accept();//本地主机:8000 remoteIp1:12345
套接字s2=ss1.accept();//本地主机:8000 remoteIp2:54321
请注意,尽管本地地址相同,但套接字的远程地址不同,因此总映射(localip:portremoteip:port)现在是唯一的


因此,在某种程度上,您可以将UDP套接字视为一种类似于TCP服务器套接字的套接字,这就是为什么您必须将其绑定到一个唯一的端口。

您必须将套接字设置为可共享的,或者按照它的名称,以便重用端口

<>在C或C++中,这是用StSoSkopt函数完成的。当您绑定到端口,然后设置SO_REUSEPORT时,另一个进程也可以将套接字绑定到相同的端口号。这方面的一个例子是多进程应用程序,使用多个CPU核尽可能快地读取传入数据。完成此操作后,流量在进程之间实现负载平衡,或者更可能的情况是,第一个读取数据的进程将获得数据(使用UDP)


对于TCP,这只与新连接的到来有关。当新连接进入时,第一个接受()连接的进程拥有该连接,但端口号仍然由绑定到该连接的所有进程共享,新连接随后被传递给第一个使用accept()获取该连接的进程。共享从TCP套接字读取的数据(尽管多线程应用程序可以做到这一点)是没有意义的,因为数据是以没有记录分隔符的流的形式输入的,因此让多个读者读取它只是一个类比,多人阅读同一本书,并在阅读时撕掉页面。你会发现每个读者都有一团混乱。

你根本不是在“做同样的事情”。绑定到本地端口与连接到远程端口不同,远程端口不使用固定的本地端口。
Socket s1 = ss1.accept();// localhost:8000 <-> remoteIp1:12345
Socket s2 = ss1.accept();// localhost:8000 <-> remoteIp2:54321