客户端和服务端之间建立连接的三次握手是咋回事?
我们来从java代码运行到观察linux内核来稍微分析一下。
Socket Server与Client
Java代码先准备好上传到linux,server代码在虚拟机node1,client代码在虚拟机node2,从略。下面重点看一下client与server是如何建立连接的。
在server
node1
机器上抓取网卡(我的虚拟机网卡名是
ens33
)数据包
tcpdump -nn -i ens33 port 9090
启动服务端
还未accept,等待着输入
启动客户端
从Kernel级观察TCP建立连接的三次握手
上面服务端和客户端都启动以后,看一下
node1
内核网络状态
netstat -natp
可以看出,其中有两个9090端口,一个处理
LISTEN
监听状态,表示我服务端准备好了,任何客户端都可以来连我了;
还有一个是
established
表示已经建立连接状态,建立连接的双方是
192.168.134.128:9090
和
192.168.134.130:47904
,其中
192.168.134.128
是服务端,端口
9090
,有一个客户端
192.168.134.130
来连它并分配了一个随机端口
47904
。
但是,这个连接没有对应的进程PID,(server端还没有accept)。
再来看一下
tcpdump
抓包情况:
清楚地看到了客户端和服务端建立连接的三次握手。
本次socket的
四元组
可以看到是
CIP 192.168.134.130 CPORT 47904SIP 192.168.134.128 SPORT 9090
在server端按回车键,执行accept
accept后发现有Java进程,PID为3862
看下进程3862的文件描述(
lsof -p 3862
):
6u
建立连接
关注一下数据丢失的问题
当客户端一次性向服务端发送超过
MTU
的字节数时,超过的数据部分将会丢失。
关于
MTU
维基百科的解释:
最大传输单元(英语:Maximum Transmission Unit,缩写MTU)是指数据链接层上面所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口有关(网络卡、串口等)。
常见媒体的MTU表
网络 MTU(Byte) 超通道 65535 16Mb/s令牌环 17914 4Mb/s令牌环 4464 FDDI 4352 以太网 1500 IEEE 802.3/802.2 1492 X.25 576 点对点(低时延) 296
查看本机网口的mtu
ifconfig
本机ens33网络mtu为1500,测试一下一次性发送超过1500个字节的情况
服务端等待接收消息(阻塞住了,还未accept)
客户端发送数据,随便粘贴一段文字,最后输入自己认得的1111111,
这个时候
netstat -natp
看一下连接情况
如图可知,此时接内核已接收了
1152
个,服务器还未accept,继续发送一段字符
abcdefg
,查看
netstat -natp
内核接收的还是
1152
个数据包,这时,让server端accept,发现接收到的数据后面的都丢失了。
Socket四元组
TCP是面向连接的,可靠地传输协议(三次握手),内核级开辟资源。
Socket四元组:
Client IP,
Client Port,
Server IP,
Server Port,这四个元素能让一个连接变得清晰、唯一。