在接受客户端后,Java serversocket如何将新的套接字绑定到同一本地端口



我对套接字和serversocket端口使用情况感到困惑。Oracle关于插座的Java教程说:

什么是套接字?

通常,服务器在特定的计算机上运行,并且具有绑定到特定端口号的套接字。服务器只需等待,聆听套接字以供客户端发出连接请求。 在客户端:客户端知道服务器正在运行的机器的主机名以及服务器正在侦听的端口号。为了提出连接请求,客户端试图用服务器的计算机和端口上的服务器进行汇合。客户端还需要对服务器进行识别,以便它粘合到本连接期间将使用的本地端口号。这通常由系统分配。

如果一切顺利,服务器都接受连接。 接受,服务器获得了一个新的套接字绑定到同一本地端口 并将其远程端点设置为地址和端口 客户。它需要一个新的插座,以便可以继续听 连接请求的原始套接字在满足需求时 连接的客户端。

在客户端,如果接受了连接,则成功创建了一个套接字,并且客户端可以使用套接字与服务器通信。 客户端和服务器现在可以通过从其插座上写或阅读来通信。

我尝试了以下代码进行测试。但这会引发一个例外。

try {
    ServerSocket serverSocket = new ServerSocket(8080);
    Socket socket = serverSocket.accept();
    // This prints 8080
    System.out.println("Local port of accepted socket : " + socket.getLocalPort());  
    // But this throws java.net.BindException: Address already in use: JVM_Bind 
    Socket myClientSocket = new Socket("www.google.com", 80, null, 8080);
} catch (Exception e) {
    e.printStackTrace();
}

我的问题很明显。从serverSocket.accept()返回的套接字可以使用相同的本地端口(8080)为什么我创建的套接字不能使用它?

要保持简单,侦听TCP插座已经明确绑定到端口,因此您无法明确将第二个TCP套接字绑定到同一端口(除非两个插座也明确地均为绑定到不同的IP地址,不包括InAddr_any)。

所接受的插座不会经过明确的"绑定"过程。他们会自动获取本地IP地址和端口,如果您连接而无需绑定,则出站插座也是如此。

您的服务器和客户端正在使用相同的本地端口进行通信。当您创建服务器套接字时,您"说"它必须在8080端口上收听。没关系。任何想要与您的服务器套接字通信的人都必须使用此类端口。

但是,在您下方,您正在创建一个客户套接字,该端口使用端口80连接到Google站点(Google在该端口上侦听),在最后一个参数中,您说该插座还必须使用本地端口8080建立连接。只有一个连接可以一次使用端口,这就是为什么您要获得java.net.bindexception,服务器和客户端连接都使用8080。

我的建议...从套接字客户端构造函数中获取最后两个参数,或更改您本地客户端端口(始终获得高号码以避免其他过程中的相同问题):

Socket myClientSocket = new Socket("www.google.com", 80);

Socket myClientSocket = new Socket("www.google.com", 80, null, 58080);