当我们调用如下代码的时候,实际java封装了很多层调用
图1
new ServerSocket(9876) 这个构造函数的内部,会调用 bind() 以及 listen() 等系统调用,之后才是 accept(),下面依次讲解。
bind(): bind 只是简单的将套接字和 地址端口联系上,调用bind()之后,netstat 不会看到任何连接
listen(): listen 表示此套接字 已经处于监听状态了,外部请求可以打进来了。
图2
可以看到,并没有运行到 accept() ,socket已经处于监听状态了,那此时如果外部连接打进来会怎样呢?我们用浏览器模拟http请求。 打开 chrome 输入 127.0.0.1:9876 回车,
图3
可以看到 55870 端口建立了连接 (ESTABLISHED 表示连接已经建立) (55868那个端口不知道怎么来的,有知道的大神希望能指点一下)。然后我们在浏览器多开几个窗口输入,会发现连接建立的更多了。
图4
所以,listen的时候,是可以接收请求并建立连接的,只是不处理这个socket的内容而已。参考UNIX网络编程(卷一,套接字联网API 第三版 p85),此时系统维护两个队列,未完成建立连接队列(三次握手只进行了第一步)和 已完成建立连接队列(上述ESTABLISTHED的连接)。而之后的 accept() 会在已建立连接队列获取套接字来处理。
accept() :会从上述已建立连接套接字队列,获取队列头部的socket,来进行处理,每次accept()都会返回一个对应客户端的全新socket 。当建立连接队列为空时,accept会阻塞并处于睡眠状态。
另注:当accept() 之后,如果一个请求打过来,服务器处理请求之后,并不会将连接中断,而是会一直通过 客户端的 keepAlived 来维持这个连接
图4
可以看到 都是从客户端发送的 keepalived 请求,服务端回应ack。
补充一下:在listen之前,创建的socket都默认为要主动 connect 其他服务的,即为主动socket,只有listen 之后,socket 才变为被动的。服务端的socket 都是listen了之后,才变为服务socket的。
作者:熊哥的世界
链接:https://www.jianshu.com/p/64ca562f156a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。