TCP复位报文段与常见网络连接错误
程序员文章站
2022-06-05 15:36:11
...
原创文章,转载请注明出处:http://jameswxx.iteye.com/blog/2065445
TCP包头中有6个标志,其中有一个复位标志(RST),这个标志其实跟网络程序中很多的错误描述相关。常见的比如:
Unable to connect to remote host: Connection refused
read error: Connection reset by peer
Connection closed by foreign host
特别是前两个错误描述,相信很多人都碰到过,但是最底层原因到底是什么呢?其实这都跟复位报文段有关。复位报文段是指RST标志生效的TCP包,复位报文段的产生场景有以下几种。
一:Unable to connect to remote host: Connection refused
出现这种错误,是因为有不存在的端口的连接请求,当连接请求到达时,目的端口没有进程正在听。对于UDP,当一个数据报到达目的端口时,该端口没在使用,它将产生一个ICMP端口不可达的信息。而TCP则使用复位。产生这个例子也很容易,我们可使用telnet客户程序来指明一个目的端口没在使用的情况:
上图说明了试图在不存在的端口上打开连接而产生的复位。该场景的复位报文段有以下几点特性:
- ACK标志没有被设置为1
- 序号被置为0
- 确认序号被置为进入的ISN加上数据字节数
尽管在到达的报文段中没有真正的数据,但SYN比特从逻辑上占用了1字节的序号空间;因此,在这个例子中复位报文段中确认序号被置为ISN与数据长度(0)、SYN比特所占的1的总和。
二 :read error: Connection reset by peer
这是因为异常终止一个连接
正常终结
正常的终止连接方式是一方发送FIN,即常规的4次挥手,有时这也称为有序释放(orderly release),因为在所有排队数据都已发送之后才发送FIN,正常情况下没有任何数据丢失。
异常终结
但也有可能发送一个复位报文段而不是FIN来中途释放一个连接。有时称这为异常释放(abortive release)。异常终止一个连接对应用程序来说有两个优点:
(1)丢弃任何待发数据并立即发送复位报文段;
(2)RST的接收方会区分另一端执行的是异常关闭还是正常关闭;
使用SOCK程序能够观察这种异常关闭的过程,Socket API通过“ linger on close”选项(SOLINGER)提供了这种异常关闭的能力。我们加上- L选项并将停留时间设为0。这将导致连接关闭时进行复位而不是正常的FIN。我们连接到处于服务器上的SOCK程序,并键入一输入行:
bsdi % sock -L0 svr4 8888 这是客户程序,服务器程序显示后面
hello, world 键入一行输入,它被发往到另一端
^ D 键入文件结束符,终止客户程序
图1 8 - 1 5是这个例子的tcpdump输出显示(在这个图中我们已经删除了所有窗口大小的说明,因为它们与讨论无关)。
第1 ~ 3行显示出建立连接的正常过程;
第4行发送我们键入的数据行( 12个字符和Unix换行符);
第5行是对收到数据的确认;
第6行对应为终止客户程序而键入的文件结束符,由于我们指明使用异常关闭,而不是正常关闭(命令行中的- L 0选项),因此主机bsdi端的TCP发送一个RST而不是通常的FIN。
RST报文段中包含一个序号和确认序号。需要注意的是RST报文段不会导致另一端产生任何响应,另一端根本不进行确认。收到RST的一方将终止该连接,并通知应用层连接复位。
我们在服务器上得到下面的差错信息:
这个服务器程序从网络中接收数据并将它接收的数据显示到其标准输出上。通常,从它的TCP上收到文件结束符后便将结束,但这里我们看到当收到RST时,它产生了一个差错。这个差错正是我们所期待的:连接被对方复位了。
三:检测半打开连接
半连接都会被复位掉,如果一方已经关闭或异常终止,而另一方却还不知道,这样的TCP连接称为半打开(Half - Open)的。任何一端的主机异常都可能导致这种情况。只要不打算在半连接上传输数据,仍处于连接状态的一方就不会检测另一方已经出现异常。
半打开连接的另一个常见原因是当客户主机突然掉电而不是正常的结束客户应用程序后再关机。这可能发生在使用PC机作为Telnet的客户主机上,例如,用户在一天工作结束时关闭PC机的电源。当关闭PC机电源时,如果已不再有要向服务器发送的数据,服务器将永远不知道客户程序已经消失了。当用户在第二天到来时,打开PC机,并启动新的Telnet客户程序,在服务器主机上会启动一个新的服务器程序。这样会导致服务器主机中产生许多半打开的TCP连接。
能很容易地建立半打开连接。在bsdI上运行Telnet客户程序,通过它和svr4上的丢弃服务器建立连接。我们键入一行字符,然后通过tcpdump进行观察,接着断开服务器主机与以太网的电缆,并重启服务器主机。这可以模拟服务器主机出现异常(在重启服务器之前断开以太网电缆是为了防止它向打开的连接发送FIN,某些TCP在关机时会这么做)。服务器主机重启后,我们重新接上电缆,并从客户向服务器发送另一行字符。由于服务器的TCP已经重新启动,它将丢失复位前连接的所有信息,因此它不知道数据报文段中提到的连接。TCP的处理原则是接收方以复位作为应答。
图18 - 16是这个例子的tcpdump输出显示(已从这个输出中删除了窗口大小的说明、服务类型信息和MSS声明,因为它们与讨论无关)。
第1 ~ 3行是正常的连接建立过程
第4行向丢弃服务器发送字符行“ hithere”
第5行是确认
然后断开svr4的以太网电缆,重新启动,并重新接上网线。接着从客户端输入下一行(即“ another line”),当我们键入回车键后,这一行被发往服务器(图18 - 16的第6行)。这导致服务器产生一个响应,但要注意的是由于服务器主机经过重新启动,它的ARP高速缓存为空,因此需要一个ARP请求和应答(第7、8行)。
第9行表示RST被发送出去。
客户收到复位报文段后显示连接已被另一端的主机终止(Telnet客户程序发出的最后信息不再有什么价值)。