listen和accept中的sokcet关系

我们学习网络编程时,一个服务端程序通常是:socket()->bind()->listen(),当有客户端程序connect()时,服务端accept()处理。下面是我在学习中遇到的几个问题,以及理解。

问题1:客户端和服务端的socket是怎么通信的?

我们知道,socket有一个四元组:(目的ip, 目的port、源ip,源port)。这个四元组就可以保证客户端和服务端之间可以通信。
比如服务端是个80的web服务,ip是1.1.1.1。服务端启动时会生成一个socket绑定到80端口监听。这时一个ip为 2.2.2.2的客户端要去访问这个服务端时,先要生成一个socket。系统会为这个socket选择一个端口,比如65535.那么客户端通个(1.1.1.1, 80, 2.2.2.2, 65535)通过connect()访问服务端。

问题2:accept中的socket和listen监听的socket的端口相同吗?

客户端通过connect()访问服务端80,通过3次握手后,进入accept队列。服务端调用accept()时,会生成一个新的socket和客户端通信,之前的socket仍然继续监听80端口。那么这个新生成的端口还是80吗?答案是肯定的,否则客户端那边的socket就无法和新生成的socket通信。看accept源码,会发现新生成的socket会拷贝监听socket的信息。因此两者的端口号相同。

问题3:服务端是怎么区分客户端的信息是给listen的socket还是accept的socket的?

如果监听的socket和新生成的socket都是使用80端口,那么客户端发给80端口的信息,怎么区分是给哪个socket?是通过客户端port做路由的。listen使用的socket是没有客户端信息的,它的客户端端口为*;而accept时新生成的socket是有客户端端口号。如下图,第一行是监听的socket,第二行是accet后生成的socket。因此通过四元组中的客户端port就可将客户端信息路由到了正确的socket上。

1
2
3
wangzhilong@in17-164^:/mnt/mfs/$ netstat --tcp -lan | grep 8787
tcp 0 0 0.0.0.0:8787 0.0.0.0:* LISTEN
tcp 0 0 10.4.17.164:8787 10.2.22.31:64285 TIME_WAIT