服务器套接字是否会在任意端口返回套接字?

7
我曾经看到很多类似于这篇关于java中serversocket的回答:“假设你有一个在5000端口上监听的服务器,客户端A和B将连接到我们的服务器。
客户端A向服务器发送请求,客户端A的端口由操作系统选择。通常情况下,操作系统会选择下一个可用的端口。搜索的起点是先前使用的端口号+1(例如,如果操作系统最近使用了端口45546,则操作系统将尝试使用45547)。
假设没有连接问题,服务器接收到客户端A在5000端口上连接的请求。服务器随后打开它自己的下一个可用端口,并将其发送给客户端。在这里,客户端A连接到新的端口,而服务器现在再次可以使用5000端口。”
我在stackoverflow的多个问题中看到过此类答案,关于在accept()返回的socket中使用不同的端口而不是ServerSocket监听的端口。我一直以为TCP由四个信息组成:
客户端IP:客户端端口和服务器IP:服务器端口 - > 协议(以区分TCP和UDP)
那么为什么accept()需要返回绑定到不同端口的套接字呢?每个头部发送的四元组信息难道不能足以区分从不同机器到达的同一服务器端口的多个连接,而不需要在服务器机器上使用不同的端口进行通信吗?

这里是一个引用了错误答案的链接(http://stackoverflow.com/a/17730496/207421)。如果还有其他类似于这个答案的“很多答案”,请提供链接,以便它们可以被投票和评论。我不知道为什么人们会猜测这样的事情,当RFC在那里等着被阅读时。 - user207421
没有猜测。这是基于错误前提的信息逻辑进展。 - Russell Uhl
1
@RussellUhl 基于未经证实的前置条件和未经审查的逻辑推断的未经验证的猜测本质上是瞎猜。那么,这个有缺陷的前提是什么呢?你何时咨询了RFC?你什么时候查看了Socket.getLocalPort()或netstat输出? - user207421
@EJP:RFC:我没有这样做,因为我是从我的类中获取信息的(很明显我错过了一些关键内容)。Socket和netstat:在与此工作了半个小时后,我得出结论,我的答案是不正确的。只有在意识到这一点之后,我才阅读了您的评论。无论如何,我已经删除了我的答案。 - Russell Uhl
2个回答

18
服务器随后打开自己的下一个可用端口,并将其发送给客户端。不,它会创建一个具有相同本地端口号的新套接字。不会分配或发送第二个端口号给客户端。SYN/ACK段是服务器响应连接请求时不包含第二个端口号的。在此之后,客户端确认SYN/ACK数据包并连接到原始端口,没有第二次连接。它一直都是这样的。我在stackoverflow上看到过类似的答案,关于accept()返回的套接字中使用了不同的端口,而不是ServerSocket正在侦听的端口。
任何这样的答案都是不正确的,应该被“极端偏见”地投票否决并进行负面评论。TCP握手在RFC 793中定义,并没有指定分配和交换第二个端口和第二个连接消息。只有三个消息,甚至不足以发生这种情况。

那么为什么accept()需要返回绑定到不同端口的套接字?

它不需要。

每个头部发送的四元组信息难道不能区分来自不同机器的同一服务器端口的多个连接,从而不需要在服务器机器上使用不同的端口进行通信吗?

可以。

你不是,但有些人是。这甚至根本没有意义。什么阻止第二个连接过程启动第三个连接,从而变成无限回归?在SYN/ACK数据包中的哪个神秘的第二端口?如何用三条消息建立两个连接?为什么SO上有那么多关于netstat显示中数千个端口80处于TIME_WAIT状态的问题?这完全荒谬。 - user207421
1
@EJP +1 因为注释了整个问题 :). 很棒的答案。 - Colin M
我已经不确定自己在指什么了。完全有可能我把TCP和应用层协议混淆了。无论如何,我自由承认我对TCP的基本理解严重有误。 - Russell Uhl
@RussellUhl 应用层协议也不能像这样行为,除非TCP这样做,或者除非它们浪费资源通过在临时端口上创建进一步的监听套接字并要求二次连接。这有什么意义呢? - user207421
@user207421 - 对于服务器端每个新的已接受连接,是否也会在客户端创建一个相应的套接字,该套接字也是客户端的四元组<S-IP,S-P,C-IP,C-P>之一? - Sheel Pancholi
@SheelPancholi 任何被服务器接受的套接字都对应于已成功连接到它的客户端套接字。显然如此。如果这不能回答你的问题,我不知道你在问什么。 - user207421

6
你对TCP数据包头信息的理解是正确的。它包含以下内容:
Client IP | Client Port | Server IP | Server Port | Protocol

或者更恰当地说(因为当你考虑双向传输时,客户端/服务器变得令人困惑):
Source IP | Source Port | Destination IP | Destination Port | Protocol

在同一服务器端口上建立多个连接时,客户端会从不同的端口发起连接。例如:

0.0.0.0:45000 -> 1.1.1.1:80
0.0.0.0:45001 -> 1.1.1.1:80

客户端端口的差异足以区分两个套接字,从而建立两个独立的连接。服务器无需在另一个端口上打开另一个套接字。它确实从accept方法中接收到一个套接字,但该套接字被分配到同一端口,并且现在是回到新接受的客户端的路线。
另一方面,FTP确实有一个模型,其中服务器将打开一个新的非特权端口(>1023),并将其发送回客户端以供客户端连接(这称为“被动FTP”)。这是为了解决客户端处于防火墙后面且无法接受来自服务器的传入数据连接的问题。然而,在典型的HTTP服务器(或任何其他标准套接字实现)中,这种情况并不适用。这是在FTP之上构建的功能。

2
@sunrize920 是的。只要源IP/端口不同,服务器就可以在同一端口接受来自各个客户端的数据。端口只是一个数字。 - Colin M

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