动手学习TCP系列之4种定时器(1)
动手学习TCP系列之4种定时器(1)
上一篇中介绍了TCP数据传输中涉及的一些基本知识点。本文让我们看看TCP中的4种定时器。
TCP定时器
对于每个TCP连接,TCP管理4个不同的定时器,下面看看对4种定时器的简单介绍。
重传定时器使用于当希望收到另一端的确认。
该定时器是用来决定超时和重传的。
由于网络环境的易变性,该定时器时间长度肯定不是固定值;该定时器时间长度的设置依据是RTT(Round Trip Time),根据网络环境的变化,TCP会根据这些变化并相应地改变超时时间。
坚持定时器(persist)使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。
保活定时器(keepalive)可检测到一个空闲连接的另一端何时崩溃或重启。
2MSL定时器测量一个连接处于TIME_WAIT状态的时间。
参见"动手学习TCP:TCP特殊状态"中对TIME_WAIT的介绍
下面就介绍一下坚持定时器和保活定时器。
坚持定时器
TCP通过让接收方指明希望从发送方接收的数据字节数(即窗口大小)来进行流量控制。
如果窗口大小为 0会发生什么情况呢?这将有效地阻止发送方传送数据,直到窗口变为非0为止。
但是,由于TCP不对ACK报文段进行确认(TCP只确认那些包含有数据的ACK报文段),如果上图中通知发送方窗口大于0的[ACK]丢失了,则双方就有可能因为等待对方而使连接死锁。接收方等待接收数据(因为它已经向发送方通告了一个非0的窗口),而发送方在等待允许它继续发送数据的窗口更新。
为防止这种死锁情况的发生,发送方使用一个坚持定时器 (persist timer)来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查(window probe)。
实验代码
下面通过Python socket实现一个快的发送端和慢的接收端,然后通过Wireshark抓包来看看窗口更新通知和窗口探查。
客户端代码如下,用户输入字符,客户端将用户输入重复1000次然后发送给服务端,通过这种简单的重复来模拟一个快的发送端:
from socket import * import time HOST = "192.168.56.102" PORT = 8081 ADDR = (HOST, PORT) client = socket(AF_INET, SOCK_STREAM) client.connect(ADDR) while True: input = raw_input() if input: client.send(input*1000) else: client.close() break
对于服务端,通过制定一个小的接收BUFFER,以及一个延时来模拟一个慢的接收端:
import sys from socket import * import time HOST = "192.168.56.102" PORT = 8081 BUFSIZ = 100 ADDR = (HOST, PORT) server = socket(AF_INET, SOCK_STREAM) print "Socket created" try: server.bind(ADDR) except error, msg: print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1] sys.exit() server.listen(1) print 'Socket now listening' conn, addr = server.accept() while True: time.sleep(3) try: data = conn.recv(BUFSIZ) if data: print data else: conn.close() break except Exception, e: print e break
评论暂时关闭