Java ServerSocket在接受客户端连接之后如何获得一个绑定到相同本地端口的新套接字?

4
我对Socket和ServerSocket端口的使用感到困惑。Oracle Java教程中关于sockets的内容如下所述:
一个Socket是什么?
通常情况下,服务器运行在一台特定的计算机上,并拥有一个绑定到特定端口号的Socket。服务器只是等待,监听Socket以等待客户端发出连接请求。 在客户端方面:客户端知道服务器正在运行的机器的主机名和服务器正在侦听的端口号。为了发出连接请求,客户端尝试在服务器的机器和端口上与服务器会合。客户端还需要向服务器标识自己,因此它绑定到一个本地端口号,在此连接期间将使用该端口号。这通常由系统分配。
如果一切顺利,服务器接受连接。一旦接受,服务器获取一个新的Socket,绑定到相同的本地端口,并且其远程端点设置为客户端的地址和端口。它需要一个新的Socket,以便可以继续监听原始Socket以等待连接请求,同时满足已连接客户端的需求。
在客户端方面,如果连接被接受,则成功创建一个Socket,客户端可以使用该Socket与服务器通信。现在,客户端和服务器可以通过写入或读取其Sockets来进行通信。

我尝试了下面的代码进行测试,但是它抛出了一个异常。

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)时,为什么我创建的套接字不能使用它?


因为这就是他们设计的方式。请清楚地说明你在引用什么内容。 - user207421
2个回答

1
为了简单起见,监听TCP套接字已经明确绑定到端口,因此您不能显式地将第二个TCP套接字绑定到相同的端口(除非两个套接字也明确绑定到不同的IP地址,不包括INADDR_ANY)。
接受的套接字不需要经过显式的“绑定”过程。它们自动获取本地IP地址和端口,就像在没有绑定的情况下连接出站套接字一样。

-1

你的服务器和客户端使用相同的本地端口进行通信。当你创建服务器套接字时,你“说”它必须监听8080端口。这没问题。任何想要与你的服务器套接字通信的人都必须使用这个端口。

但是,在下面,你正在创建一个客户端套接字,使用80端口连接到谷歌网站(谷歌正在监听该端口),并且在最后一个参数中,你说这个套接字也必须使用本地端口8080来建立连接。一次只能使用一个端口进行连接,这就是为什么你会得到java.net.BindException,因为服务器和客户端连接都在使用8080。

我的建议是...从你的套接字客户端构造函数中取出最后两个参数,或者更改你的本地客户端端口(始终获取一个高数字以避免与其他进程发生相同的问题):

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

或者

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

OP在询问为什么使用服务器accept创建的端口允许具有本地端口8080 - RealSkeptic
我认为当我说:“一次只能有一个进程使用一个端口,这就是为什么你会得到java.net.BindException”的时候,我已经回答了这个问题。他正在同时使用8080本地端口作为服务器和客户端(入站和出站)的端口。 - VeryNiceArgumentException
@RaphaelMoita 所有这些代码都在同一个进程中运行。你还没有回答问题。 - user207421
完全改变你回答的基础很难被称作“澄清你的意思”,而且仍然是错误的。 - user207421
在低级别的编程中,一次只能建立一个连接。发生的情况是套接字服务器立即分派到更高的内部端口并释放外部端口(在这种情况下为8080)以接收下一个连接。 - VeryNiceArgumentException
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接