TCP Socket通过(Source IP, Source Port, Dest IP, Dest Port)来唯一标识。 所以多个client可以连接到同一个Server的同一个port。 根据TCP的流程,TCP服务端首先会生成一个listen socket, 绑定端口,然后监听该端口,当有连接到来,accept之后会生成新的connect socket。那么我就有疑问了,listen socket 和 connect socket 是使用同一个端口吗? 如果是,客户端发过来的数据,传输层接收到以后,OS怎么知道接下来由哪个Socket来接收?
我找了一圈google,终于在这篇文章找到了答案。
Server Socket List:
local address | local port | foreign address | foreign port | listen?
-- bind
0.0.0.0 1234 0 0
-- listen
0.0.0.0 1234 0 0 YES
-- connect
0.0.0.0 1234 0 0 YES
192.168.15.67 1234 135.250.68.43 7801
注意连接这一步,第一行是listen socket,第二行是connect socket。当客户端发送连接请求时,将server address和port传递给connect方法,connect会向服务端发送connect control message。服务端收到connect control message之后,将扫描PCB表,是否端口符合,外部地址匹配(0匹配一切),并且socket是否在监听状态。自然listen socket是符合的,当向listen socket 发送了连接请求后,经过几个来回,一个新的socket创建出来,这个新的socket完整的描述了客户端与服务端的连接信息,并且标明了不是用来监听。接下来,服务端会向客户端发送一条ACK消息,消息本身就带了服务端的地址和端口(客户端虽然向connect传递了参数,但本地的socket并不知道server的具体地址)。当客户端接收到该信息时,也更新了本地的Socket,之后就可以互相发送数据了。
Client Socket List:
local address | local port | foreign address | foreign port | listen?
-- bind
0.0.0.0 7801 0 0
-- listen
0.0.0.0 7801 0 0
-- connect (send a control message to server, receive ACK)
0.0.0.0 7801 192.168.15.67 1234
可以看出在connect没有完成前,服务端和客户端的socket都是不完整的,这个阶段之间往返的控制消息有可能是OS直接发给传输层,不必经过socket。另外,server的listen socket由于不处理实际数据,可以良好的一直运转下去。进程本身可以创建共享端口的多个Socket,而多个进程这么做不是不可以,但会有问题,因为数据只能发送给一个进程。