命令行:
root@ubuntu:/home/linson# netstat -apt | grep 3030
server,listen
服务端根据端口生成一个socket.用于监听连接.也就是监听3次握手,当3次握手成功,建立一个连接接放入队列中.
也就是说执行了listen,会自动应答3次握手,如果不执行listen,没有api会帮你处理3次握手.
所以客户端的connect应该也是自动执行3次握手.
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
server 还没应答之前
可以看到连接已经建立,但是服务端的连接却没有pid和程序名字.
说明3次握手和连接的建立都和accept方法没有关系.
也说明一个端口可以建立很多连接.listen建立起来的,被api赋予专门的用途.就是接受和应答3次握手,并建立新连接.
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
tcp 0 0 localhost:3030 localhost:33092 ESTABLISHED -
tcp 0 0 localhost:33092 localhost:3030 ESTABLISHED 11504/esocket6
应答之后
可以看到监听链接(由listen建立的)和客户端握手之后建立的新连接终于有pid了.也就是理论上.可以一个程序监听.一个程序accept.可是其他程序获取不到监听连接的描述符.所以...
所以accept,完全和tcp没有关系,只是和系统内核打交道.从队列中取链接而已.
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
tcp 0 0 localhost:3030 localhost:33092 ESTABLISHED 11170/epoll
tcp 0 0 localhost:33092 localhost:3030 ESTABLISHED 11504/esocket6
客户端关闭.服务断还未应答.
可以看到客户端发送close,其实是发送一个字节.服务端的req是1,说明有一个字节从客户端发送来了,而没有读取.应该就是eof标记字节.
并且可以知道,服务端内核通过客户端的ip和port区分对于自己同一个端口的不同连接,并且应该是通过某个标记来注明特殊的listen链接.
如果握手,那么给listen文件描述符,如果接受信息.那么定位一下特定的文件描述符.
也就说明端口是系统的端口.来定位系统中的程序的。
socket是某个端口的socket.端口可以有很多socket,比如服务端。一个端口可以有很多socket,来区分客户端。而客户端也可以用一个端口来连不同的服务端。也可以用不同的端口连同一个服务端。
而文件描述符是一个读写属性的东西.可以由socket的listen得到.也就是一个由系统自动接受3次握手,也就是可以有读写属性的东西.用于和任何客户通讯.
并且文件描述符,也可以由文件描述符本身得到.也就是 liston文件描述符,的accept方法.由系统生成一个描述符,用于和特定客户通讯.
客户端关闭,那么客户端是期待服务端发送结束命令。进入等待fin阶段。也就是FIN_WAIT2
而服务端是等待服务程序响应关闭,如果不手动响应,那么就等待tcp协议自己经过20秒左右的自己应答。
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
tcp 1 0 localhost:3030 localhost:33092 CLOSE_WAIT 11170/epoll
tcp 0 0 localhost:33092 localhost:3030 FIN_WAIT2 11504/esocket6
服务端应答,之后,服务端彻底释放了socket.客户端进入time_wait阶段。等待是否还有路上的数据没接受到。
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
tcp 0 0 localhost:33092 localhost:3030 TIME_WAIT -
服务端应答 之后某几分钟之内. 客户端也彻底释放socket.
tcp 0 0 localhost:3030 *:* LISTEN 11170/epoll
知识点
1)程序奔溃会发送fin标记。
2)客户断的 TIME_WAIT是等待2msl.因为最后一个分组信息是客户端发送的.发送完毕之后.服务端并不会回应.所以
客户端辛苦一点,迟点下班,万一路由发生错误,还可以再发一次.
3)客户端连续发送2次close,是会导致发送rst?这个要再测试下.
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 0 0 192.168.87.130:3046 192.168.87.130:40604 ESTABLISHED -
tcp 0 0 192.168.87.130:40604 192.168.87.130:3046 ESTABLISHED 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 0 0 192.168.87.130:3046 192.168.87.130:40604 ESTABLISHED -
tcp 0 0 192.168.87.130:40604 192.168.87.130:3046 ESTABLISHED 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 2 0 192.168.87.130:3046 192.168.87.130:40604 ESTABLISHED -
tcp 0 0 192.168.87.130:40604 192.168.87.130:3046 ESTABLISHED 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 3 0 192.168.87.130:3046 192.168.87.130:40604 CLOSE_WAIT -
tcp 0 0 192.168.87.130:40604 192.168.87.130:3046 FIN_WAIT2 -
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 3 0 192.168.87.130:3046 192.168.87.130:40604 CLOSE_WAIT 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 3 0 192.168.87.130:3046 192.168.87.130:40604 CLOSE_WAIT 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
tcp 0 0 192.168.87.130:3046 192.168.87.130:40604 CLOSE_WAIT 22452/linsonnetlib
root@ubuntu:/home/linson# netstat -apt |grep 3046
tcp 0 0 192.168.87.130:3046 *:* LISTEN 22452/linsonnetlib
root@ubuntu:/home/linson#
在linux 下有个ipython,
确实是个神器。
开2个终端。输入以下相关代码,
就可以立马实时查看网络通讯状态。
再开一个终端。输入netstat相关命令查看双方状态。
方便的一塌糊涂。
ipython
import socket,select
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('',6000))
s.listen(10)
c1,a1=s.accept()
c1.setblocking(0)
import socket,select
c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect(('',6000))
c.shutdown(socket.SHUT_WR)
关闭的四次握手。
可以是客户端,2次关闭(一次shutdown,一次close),或2次close
这样服务端可以处于被动关闭状态。因为多线程环境下。短链接,服务端比较难判断是否消息全部发送完毕。
而客户端可以异步接受后,再一次主动关闭连接。会发送reset信号,服务端如果是epoll管理,取消关注事件后。好像会立即断开。而如果是一般监听。会进入closewait.
client server
shutdown
fin->
fin1
-<act
colsewait
fin2
close->
fin2->
-<act
over close wait
1)发起关闭的一方,会进入fin_wait1 阶段。
对端由tcp 协议回应,
对端进入 close_wait 阶段。
发起一方进入fin_wait2阶段。
2)对端接受0.关闭 进入lastack,
而起初发送的一方由tcp协议回应,进入time _wait
对端直接close.
所以经常见到的是close_wait,fin_wait2,time _wait这3个状态。
其他状态,由于tcp协议自动的回应,是立马消失的
3)发送数据如果对方缓冲满。发送会失败。而不是说我们的发送缓冲区没满就会接受。
经过测试,对方满。滑动窗口为0的时候。我们的发送就失败。这个时候,我们的发送缓冲区还是有些数据的,是由于网络通知的时间差,导致发现不能发送的时候,程序已经send不少了。但之后的send函数会失败。
这个时候不但我们应用层挤压了数据。连发送缓冲区也挤压了。所以tcp的绝对可靠不是对用户来说。而是对于机制来说。
这个时候如果取消接受事件,但是之前还是有挤压的接收事件存在。