为什么Java的ServerSocket accept()方法返回的套接字的端口号与ServerSocket相同?

5
在服务器端,我使用以下代码:
ServerSocket server = new ServerSocket(1234);
Socket server_socket = server.accept();

我发现服务器正在监听端口1234。

当一个或多个客户端套接字连接时,它们都在使用相同的端口1234!

这真的很令人困惑:

enter image description here

我记得多个套接字不能使用相同的端口,是吗?谢谢。


6
为什么不呢?阅读一下TCP的工作原理就知道了。 - John Dvorak
1
你要寻找的简单答案是你没有注意到右边的LISTEN..只有一个。 - Stefanos Kalantzis
3
我调用了 accept() 两次,所以实际上有两个套接字存在,看看我的截图。 - WoooHaaaa
2
如果调用@StefanosKalantzis两次,则会返回两个套接字。 - John Dvorak
1
如果你调用三次,它会返回三个套接字,而不是说它“返回两个套接字”。这并不是一个合理的解释。你的问题的答案是协议就是这样定义的,在这种情况下多个套接字确实可以使用相同的端口,你可以自己看到。这不是一个真正的问题。 - user207421
显示剩余3条评论
1个回答

11
TCP连接由四个数字标识:
- 客户端(或对等端1)的IP地址 - 服务器(或对等端2)的IP地址 - 客户端端口 - 服务器端口
典型的TCP连接如下所示:
- 客户端IP由客户机的ISP或NAT提供。 - 服务器IP由用户提供或在DNS中查找。 - 客户端从未分配的范围中任意选择一个端口(避免重复的四元组)。 - 服务器端口由协议或显式指定。
在ServerSocket中指定的端口是客户端连接的端口。它仅仅是一个端口号,操作系统知道属于您应用程序的对象,并将OS事件传递到您的应用程序。
ServerSocket#accept方法返回一个Socket。Socket是一个包装单个TCP连接的对象。也就是说,客户端IP、服务器IP、客户端TCP端口和服务器TCP端口(以及一些传递相关数据的方法)
客户端发送的第一个TCP数据包必须包含您的应用程序所监听的服务器端口,否则操作系统将不知道该连接属于哪个应用程序。
此后,没有理由将服务器TCP端口切换到另一个数字。这对服务器机器或客户机器都没有帮助,还需要一些开销进行处理(需要同时发送新旧TCP端口),并且有额外的开销,因为服务器操作系统不能再使用单个端口标识应用程序——它需要将应用程序与所有使用的服务器端口关联起来(客户机仍然需要这样做,但是典型的客户机连接数量少于典型的服务器连接数量)。
您看到的是:
- 两个入站连接,属于服务器(本地端口:1234)。在服务器应用程序中,每个连接都有自己的Socket。 - 两个出站连接,属于客户端(远程端口:1234)。在客户端应用程序中,每个连接都有自己的Socket。
  • 一个监听连接,属于服务器。这对应于接受连接的单个ServerSocket
  • 由于它们是回环连接,在单台计算机上可以看到两个端点混合在一起。您还可以看到两个不同的客户端端口(52506和52511),既在本地端也在远程端。


    1
    我的图片中的两个 127.0.0.1.1234 是同一个套接字吗? - WoooHaaaa
    @MrROY,它们是来自同一个ServerSocket的不同Socket(请注意每个套接字的另一个端口也不同)。 - John Dvorak
    谢谢!您的意思是同一个ServerSocket中的这两个(或更多)套接字可以(或必须)使用相同的端口吗? - WoooHaaaa
    1
    @MrROY 由同一ServerSocket返回的套接字必须具有与ServerSocket相同的服务器端口,但是来自同一ServerSocket的两个套接字始终会在客户端IP或客户端端口上有所不同(除非服务器IP不同-您的服务器具有两个面向同一网络的不同网络卡,或者您拥有那些假装是两个的卡之一)。 - John Dvorak

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