服务器如何确定要发送到哪个客户端端口?


26

据我了解,这是客户端发出连接请求时发生的情况:

  1. 服务器将绑定到特定的端口号。端口号始终绑定到侦听进程。由于只有服务器正在侦听传入的连接,因此我们不需要在客户端进行绑定
  2. 服务器将在该端口号上继续执行listeninig。
  3. 客户端将发送一个connect()请求。
  4. 服务器将使用接受请求accept()。一旦服务器接受客户端的请求,内核分配服务器进一步随机端口号send()receive(),因为不能用于发送和监听服务器上的相同的端口号,和先前端口仍然是聆听新的联系

考虑到所有这些,服务器如何找出客户端接收的端口?我知道客户端将发送带有源端口和目标端口的TCP段,因此服务器将使用该段的源端口作为其目标端口,但是服务器调用什么功能来查找该端口?是accept()


Answers:


33

它是数据包中TCP(或UDP等)标头的一部分。这样服务器就可以找到,因为客户端告诉了它。这类似于查找客户端的IP地址(属于IP标头的一部分)的方式。

例如,每个TCP数据包都包含一个IP标头(至少具有源IP,目标IP和协议[TCP])。然后是一个TCP标头(带有源端口和目标端口,以及更多)。

当内核收到一个SYN数据包(TCP连接的开始),其远程IP为10.11.12.13(在IP标头中)和远程端口为12345(在TCP标头中)时,它便知道了远程IP和端口。它发回SYN | ACK。如果listen返回ACK,则该调用将返回为该连接设置的新套接字。

TCP套接字由四个值(远程IP,本地IP,远程端口,本地端口)唯一标识。您可以具有多个连接/插槽,只要其中至少一个不同即可。

通常,与服务器进程的所有连接的本地端口和本地IP都相同(例如,与sshd的所有连接都位于local-ip:22上)。如果一台远程计算机进行多个连接,则每台将使用不同的远程端口。因此,除了远程端口外,其他所有端口都是相同的,但这很好-只需四个端口之一就可以不同。

您可以使用例如wirehsark来查看数据包,它将为您标记所有数据。这是突出显示的源端口(请注意,已解码的数据包中突出显示了源端口,底部显示了十六进制转储):

Wireshark显示一个TCP SYN数据包


>感谢您的解释。因此,您的意思是说,在accept()之后获得的新服务器套接字描述符(即元组)将具有客户端端口和客户端地址详细信息,并使用新的套接字描述符服务器来发送和接收数据到并从客户端。新的套接字文件描述符将具有由内核,服务器ip,客户端ip和客户端端口分配的新服务器端口号。
苏比·苏雷什

@SubiSuresh是的,元组存储在内核中,并与该文件描述符关联。
德罗伯特

>感谢derobert。所以我得出结论,新的服务器套接字描述符将具有服务器从accept()获取的客户端端口和客户端地址。我的理解很好吗?
苏比·苏雷什

@SubiSuresh是的,这是正确的。从应用程序的角度来看,您通常不在乎(除了日志记录)。内核确保将您write(等等)的数据放到正确的位置。
德罗伯特

>感谢您的帮助,我想我明白了。;-)
苏比·苏雷什

2

“连接请求(connect()通常是客户端程序的系统调用)引起三向握手。三向握手(从客户端到服务器)的第一个数据包设置了SYN标志,并包括客户端程序的TCP端口号。内核分配给它。

您可以在有关Nmap与Natural SYN数据包文章中看到这一点。Nmap SYN数据包解码的短语为“ source.60058> dest.22”。“合法的SYN数据包”解码中包含短语“ source.35970> dest.80”。这两个SYN数据包告诉远程内核该数据包分别来自TCP端口60058和35970。


>但是布鲁斯发生在后端。但是我的服务器实际上是如何在客户端服务器程序中正常获取端口号之类的细节的,因为我从未见过任何用于获取客户端端口和客户端地址的功能
Subi Suresh,

系统调用getpeername()应允许您在任何打开的套接字上执行此操作。accept()服务器代码必须使用该系统调用来获取套接字文件描述符以与客户端进行通信,该系统调用具有一个参数(在我的手册页中为“ sockaddr”),该参数包含预期客户端的IP地址和TCP端口号。
Bruce Ediger

>请不要介意我是否elloborate。从我得到的所有输入中,我了解到accept()的结构sockaddr_in充满了客户端详细信息,accept()之后返回的新服务器套接字描述符将自动具有客户端端口和地址。这就是为什么我们能够使用send(新服务器套接字描述符)发送的原因。我希望做到这一点?这只是为了确保我所理解的是正确的。
苏比·苏雷什

@SubiSuresh-我相信你写的是事实。
Bruce Ediger

1

TCP套接字是面向流的套接字。两个套接字描述符(由您和您的对等方拥有)已可靠连接。因此,您不必担心客户端的端口-只需编写套接字描述符即可!

另外,如果您确实想知道(可能用于记录),请随时获取getsockname(2)。


0

连接由元组(源IP,源端口,目标IP,目标端口)定义。答案相反。


@vondrand我了解了von,但是服务器从哪个函数知道客户端端口号?在不知道客户端端口号如何发送的情况下,服务器是否使用accept()中的结构来获取客户端港口 ?
苏比·苏雷什
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.