SocketChannel Timeout——TCP半开链接

简介

TCP半开连接

​ According to RFC 793, a TCP connection is referred to as half-open when the host at one end of that TCP connection has crashed, or has otherwise removed the socket without notifying the other end. If the remaining end is idle, the connection may remain in the half-open state for unbounded periods of time.

​ 从(TCP协议规范)RFC 793 可知,当TCP连接一端的主机崩溃,又或者一端移除socket套接字而不通知另一端,这样的TCP连接称为TCP半开连接。如果另外一端任然处于空闲等待的状态,那么这个半开连接状态将永久保持。

三次握手

SocketChannel Timeout——TCP半开链接_第1张图片

四次挥手(自己实在画不出美的图,只能借用一下)

SocketChannel Timeout——TCP半开链接_第2张图片

场景重现

一些必要的准备工作的介绍

​ 在场景重现的时候,我采用了本地windows 10,云端的Centos 7.0。

​ 本地主要用socketChannel作为socket客户端,用Wireshark抓包,过滤规则为:

ip.addr == ${my ip address} and tcp.port == 17878

​ socket客户端的代码如下:

import java.nio.*;
import java.nio.channels.*;
import java.net.*;

/**
 * 

ClassName DisplayElement *

Description *

Author ChongLou *

Version *

Date 2017/7/12 21:59 */ public class TestTCPConnect { public static void main(String[] args) { try { SocketChannel sc = SocketChannel.open( new InetSocketAddress( yourIPaddress, 17878 ) ); ByteBuffer buf = ByteBuffer.allocateDirect( 1024 ); byte[] buff = new byte[1024]; int numBytesRead = 0; while ((numBytesRead = sc.read( buf )) != -1) { buf.flip(); while (buf.remaining() > 0) { System.out.print( (char) buf.get() ); } buf.clear(); System.out.println(); } } catch (Exception e) { System.err.println( "Connect Excption:" + e ); } } }

​ 云端主要采用nc(netCat)作为socket 服务端,监听语句:

nc -l  17878(yourport)  
// -l ==listener

​ 云端抓包工具tcpdump,抓包语句:

tcpdump -i eth1 -vv port 17878 -w netPackageFile.cap
  //其中 -i eth1 表示指定网卡为eht1
  // port 17878 抓包的端口
  // -w netPackageFile.cap 抓包输出到netPackageFile.cap,为了方便wireshark打开。
  // -vv  输出详细的报文信息。(这里还不太确定到底需不需要-vv)

模拟步骤

  1. 以上述规则,打开两端抓包工具;

  2. 打开socket服务端监听程序–>nc -l 17878;

  3. 打开socket客户端,这时抓包工具会出现三次握手的相关包和信息

  4. 在nc输入文本,测试两端通信状态。

    这里写图片描述

  5. 将client端的出站端口给禁掉。

  6. 继续在nc端写入消息到socket。

    SocketChannel Timeout——TCP半开链接_第3张图片

    当第二次写入时,client端因为出站端口被禁用,所以客户端会抛异常。但是,server端并不知道client端的情况,依旧不停地往socket里面写。

  7. 再次尝试往socket里面写!
    SocketChannel Timeout——TCP半开链接_第4张图片

可以看出无论server端往socket里面写多少,都不会知道client端已经挂掉了。

分析

以下是server端的抓包情况

SocketChannel Timeout——TCP半开链接_第5张图片

以下是client端的抓包情况

SocketChannel Timeout——TCP半开链接_第6张图片

​ 前两行是两端进行三次握手,中间4行是进行正常的数据传输。之后就是server端在一定的时间间隔中不停地请求发送未收到返回的消息,client因端口关闭而出现异常,在一定的时间间隔内向server端发送fin包(client这里还不太确定其行为状态)。

至此,形成了TCP半开连接的状态。

解决办法,将在之后的博客中提出,并给出模拟代码。

总结

​ 真是一次漫长的场景重现。详细的走了一遍三次握手、四次挥手,了解了linux转包工具tcpdump,利用wireshark进行包分析。

你可能感兴趣的:(小白初入计网)