平时我们使用的tcpdump
、ping
、traceroute
属于TCP/IP协议族,虽然叫TCP/IP协议族,但是这个协议族还涉及到许多其他成员。下图是其概貌。
下图是ping百度主页的结果:
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
64 bytes from 14.215.177.39: icmp_seq=0 ttl=55 time=4262.004 ms
64 bytes from 14.215.177.39: icmp_seq=1 ttl=55 time=3726.616 ms
64 bytes from 14.215.177.39: icmp_seq=2 ttl=55 time=4887.194 ms
64 bytes from 14.215.177.39: icmp_seq=3 ttl=55 time=4479.124 ms
Request timeout for icmp_seq 8
64 bytes from 14.215.177.39: icmp_seq=4 ttl=55 time=5194.957 ms
说ping
一个端口,是不妥的。如果有人说ping
一下80端口通不通,其实指的是发送一个TCP请求探测一下80端口能不能回包。
真正的ping
使用的是ICMP,没有端口一说。
UDP客户与服务器之间不必存在长期的关系。
UDP本身不提供确认、序列号RTT估算、超时及重传机制。
实时音视频聊天、一些在线游戏等时间敏感的应用,适用于UDP。这些场景下,使用者可以忍受一定程度的数据丢包,但是不能容忍过多的延迟。
正如第一章的时间日期程序——“接受客户连接,发送应答”步骤所说:
TCP连接使用三路握手(three-way handshake)来建立,当握手完毕时,accept函数返回,其返回值是一个称为已连接(connected descriptor)的新描述字(connfd)。此描述字用于与新客户的通信。accept为每个连接到服务器的客户返回一个新的已连接描述字。
TCP发送数据,有超时及重传机制,数次重传失败后,TCP才放弃。这一点使得TCP比UDP可能消耗更多的时间。
TCP根据数据分节的序列号,进行排序,去重,将完整的数据传递给应用进程。
TCP有接收缓冲区,缓冲区满后,必须等到应用进程从缓冲区读取数据后才能继续接收新的数据。
UDP发送数据不管接收方的缓冲区是不是能装下。
最后,TCP的连接是全双工的,意味着接收方也可以在下一时刻成为发送方,这一前提下,追踪每个方向上数据流的状态信息(序列号、通告窗口)大小,就显得尤为重要了。
建立一个TCP连接的步骤:
socket
、bind
、listen
,准备好接受外来的连接。connect
,发送一个SYN分节,告知服务器建立连接后数据的初始序列号。下面是第一个分节的抓包,包含了一些选项
16:25:52.755769 IP localhost.60933 > localhost.daytime: Flags [S], seq 1267114631, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 4110257572 ecr 0,sackOK,eol], length 0
0x0000: 4500 0040 0000 4000 4006 0000 7f00 0001 E..@..@.@.......
0x0010: 7f00 0001 ee05 000d 4b86 a287 0000 0000 ........K.......
0x0020: b002 ffff fe34 0000 0204 3fd8 0103 0305 .....4....?.....
0x0030: 0101 080a f4fd 8da4 0000 0000 0402 0000 ................
终止一个TCP连接的步骤:
close
,我们称这一端执行主动关闭,它发出第一个FIN分节。close
关闭它的套接口,向主动方发送一个FIN。上图演示了客户端发起的主动关闭,实际上无论是客户端还是服务器都可以执行主动关闭。譬如HTTP(超文本传送协议)就是服务器执行主动关闭。
CLOSED
状态下执行一个主动打开:
在SYN_SENT
情况下收到附带ACK的SYN:
应用进程调用close
主动关闭:
应用进程在ESTABLISHED
状态下接收到FIN:
在TCP的建立连接的三次握手和终止连接的四次挥手之间,是数据分节的传输。此时服务器对客户请求的确认是伴随着服务器的应答发送的。这称为捎带,通常在服务器处理请求并产生应答的时间少于200ms时发生。如果服务器耗用更长的时间,如1s,就会先确认,再应答。
TCP数据传输
上图这样的单一分节的请求和接收,使用TCP时,包括连接建立和连接终止的7个分节,以及最后一次客户对服务器数据的应答,有8个分节额外需要消耗。如果使用UDP,只有2个分组需要交换。
许多应用程序还是在使用UDP,因为它们需交换的数据量很小,也避免TCP连接建立和终止连接的额外开销。
执行主动关闭的那端会在转换成CLOSED
之前进入这个状态。
MSL
的两倍,俗称2MSL
。MSL
的值选择在30s~2min之间,这意味着TIME_WAIT
状态的延迟在1min~4min之间。MSL
是IP数据报能在互联网中生存的最长时间。ACK
丢失,被动方就会重发最终的FIN
,因此主动一方必须维护状态信息,以允许它重发对应的ACK
。为了实现全双工关闭(两个方向数据流都彻底关闭),TCP必须正确处理这四个分节中任何一个分节的丢失情况。MSL
,那么TIME_WAIT
等待2个MSL
之后,便可以保证老的重复分节已经在网络中彻底丢弃。这样下一次在相同的IP地址和端口建立的连接,必然不会接收到老的请求分节了。并发服务器中,主服务器通过循环派生子进程来处理每个新的连接。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。