TCP连接建立与终止详解教程

在开始介绍TCP连接之前,先来看看TCP数据包的首部,首部里面有很多重要的字段,在我们实现程序的时候需要进行设置。

TCP的首部

在OSI七层模型中,上层的数据包都会作为下层数据包的数据部分(payload)。

也就是说,当构造TCP数据包的时候,会把应用层的数据包作为TCP包的数据部分,然后加上TCP头构成TCP数据包;同样,当构造IP数据包的时候,整个TCP包就会被当作数据部分,然后加上IP头构成IP数据包。

TCP头的数据格式如下,在不包括可选字段的情况下,一般TCP头会占用20个字节。

在TCP首部中,有几个字段是需要关注一下:

    在TCP首部中没有源和目标的IP、MAC地址(IP和MAC地址分别是网络层和链路层首部的信息),只有源和目标的端口
    Sequence Number是包的序号,网络层(IP层)的传输是不可靠的,可能产生包乱序,所以这个需要可以解决网络包乱序的问题
    Acknowledgement Number用来确认收到数据包的确认序号,为TCP的传输提供了可靠性保证
    TCP Flags包括了8个bit,通过对这些bit的设置,可以代表不同类型的TCP数据包

下面就看看TCP连接的建立和终止。

TCP连接建立

TCP连接建立的过程被称为三次握手过程:

    连接建立发起端发送[SYN]包,该端将主动打开(active open)
    接收端将发送[SYN, ACK]包,该端将被动打开(passive open),ACK标志表示对收到的[SYN]包的确认
    连接建立发起端发送[ACK]包确认[SYN, ACK]包

Initial Sequence Number

连接建立过程中,一个重要的工作就是初始化Sequence Number,通信的双方在建立连接的过程中互相通知对方自己的初始Sequence Number(ISN:Initial Sequence Number)。ISN不是固定的,ISN跟时钟绑定,根据特定的间隔自增,直到超过2^32,又从0开始。

SYN全称就是Synchronize Sequence Number,通过seq序号,TCP就可以保证数据包的顺序;通过ack序号,TCP就有了可靠性。

连接建立注意点

在建立TCP连接的过程中,有以下两点需要注意一下:

    [SYN]标志的数据包会使用消耗一个序号,所以对端的确认号(ack)是当前序号(seq)加一
    当被动打开端发送[ACK]确认包的时候,同时设置了[SYN]标志,所以TCP连接建立的过程只需要三次握手,而不是四次

TCP连接终止

TCP连接终止的过程被称为四次挥手过程,以下图为例:

    连接终止端(client)发送[FIN, ACK] 包,关闭client到server方向的数据发送通路
    server端发送[ACK]包来确认来自client的[FIN, ACK] 包
    server端发送[FIN, ACK] 包,关闭server到client方向的数据发送通路
    client端发送[ACK]包来确认来自server的[FIN, ACK] 包,到此TCP连接关闭

连接终止注意点

在建立TCP连接的过程中,有以下两点需要注意一下:

    [FIN]标志的数据包会使用消耗一个序号,所以对端的确认号(ack)是当前序号(seq)加一
    与建立连接时的三次 握手不同,终止连接需要四次挥手
        因为TCP连接是全双工的,每个方向都必须单独进行关闭。当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,但是TCP连接在收到一个FIN后仍能发送数据

TCP连接实验

好了,了解了TCP连接建立和终止的基本知识后,就可以通过Pcap.Net来进行TCP连接建立和终止的实验了。

建立连接代码的基本流程如下:

    client程序使用一个初始的seq序号(100),然后生成并发送一个带[SYN]标志的TCP包
    client将期待来自服务端的[SYN, ACK]包
    当收到[SYN, ACK]包之后,client需要生成并发送一个[ACK]包进行确认,这个[ACK]包的ack号是[SYN, ACK]包seq号加一

终止连接代码的基本流程如下:

    client程序delay 10秒钟,然后发送[FIN, ACK]包关闭client到server的通路,继续使用全局的seq号
    client将期待来自服务端的[ACK]包,以及[FIN, ACK]包
    最后client发送[ACK]包,seq号需要加一,因为[FIN]标志的包将消耗一个序号,TCP连接终止完成

主程序如下,发送TCP连接建立和终止请求,每个请求发送后都用PacketHandler处理收到的包:

communicator.SendPacket(Utils.BuildTcpPacket(endPointInfo, TcpControlBits.Synchronize, null));
PacketHandler(communicator, endPointInfo);
// delay 10 secs, then client to send Fin
Thread.Sleep(10000);
communicator.SendPacket(Utils.BuildTcpPacket(endPointInfo, TcpControlBits.Fin | TcpControlBits.Acknowledgment));
PacketHandler(communicator, endPointInfo);

程序的主要逻辑在PacketHandler中,这个函数根据收到的不同TCP包的类型完成不同的逻辑,产生并发送不同类型的包。

例如,当PacketHandler接收到来自服务端的[SYN, ACK]包后,处理函数就会生成并发送一个[ACK]确认包。也就是说,PacketHandler的逻辑就是实现了TCP连接建立和终止的逻辑。

private static void PacketHandler(PacketCommunicator communicator, EndPointInfo endPointInfo)
{
    Packet packet = null;
    bool running = true;
    do
    {
        PacketCommunicatorReceiveResult result = communicator.ReceivePacket(out packet);
        switch (result)
        {
            case PacketCommunicatorReceiveResult.Timeout:
                // Timeout elapsed
                continue;
            case PacketCommunicatorReceiveResult.Ok:
                bool isRecvedPacket = (packet.Ethernet.IpV4.Destination.ToString() == endPointInfo.SourceIp) ? true : false;
                if (isRecvedPacket)
                {
                    switch (packet.Ethernet.IpV4.Tcp.ControlBits)
                    {
                        case (TcpControlBits.Synchronize | TcpControlBits.Acknowledgment):
                            Utils.PacketInfoPrinter(packet);
                            Packet ack4SynAck = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment);
                            communicator.SendPacket(ack4SynAck);
                            break;
                        
                        case (TcpControlBits.Fin | TcpControlBits.Acknowledgment):
                            Utils.PacketInfoPrinter(packet);
                            Packet ack4FinAck = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment);
                            communicator.SendPacket(ack4FinAck);
                            break;
                        case TcpControlBits.Acknowledgment:
                            Utils.PacketInfoPrinter(packet);
                            break;
                        default:
                            Utils.PacketInfoPrinter(packet);
                            break;
                    }
                }
                else
                {
                    switch (packet.Ethernet.IpV4.Tcp.ControlBits)
                    {
                        case (TcpControlBits.Fin | TcpControlBits.Acknowledgment):
                            Utils.PacketInfoPrinter(packet);
                            break;
                        case TcpControlBits.Synchronize:
                            Utils.PacketInfoPrinter(packet);
                            break;
                        case TcpControlBits.Acknowledgment:
                            Utils.PacketInfoPrinter(packet);
                            running = false;
                            break;
                        default:
                            Utils.PacketInfoPrinter(packet);
                            break;
                    }
                }
                break;
            default:
                throw new InvalidOperationException("The result " + result + " should never be reached here");
        }
    } while (running);
}

在PacketHandler函数中用到了BuildTcpResponsePacket这个函数,这个函数根据收到的TCP包,来构建response包。

这个函数有下面几个注意点:

    该函数会根据收到的包,设置response包的源和目的地址
    该函数会接受PacketHandler传递来的TCP flags,并设置到TCP首部中
    该函数的另一个重要部分就是会计算并设置TCP首部中的seq好ack号,这一点很重要

public static Packet BuildTcpResponsePacket(Packet packet, TcpControlBits tcpControlBits)
{
    EthernetLayer ethernetHeader = new EthernetLayer
    {
        Source = new MacAddress(packet.Ethernet.Destination.ToString()),
        Destination = new MacAddress(packet.Ethernet.Source.ToString()),
        EtherType = EthernetType.None, // Will be filled automatically.
    };
    IpV4Layer ipHeader = new IpV4Layer
    {
        Source = new IpV4Address(packet.Ethernet.IpV4.Destination.ToString()),
        CurrentDestination = new IpV4Address(packet.Ethernet.IpV4.Source.ToString()),
        Fragmentation = IpV4Fragmentation.None,
        HeaderChecksum = null, // Will be filled automatically.
        Identification = 123,
        Options = IpV4Options.None,
        Protocol = null, // Will be filled automatically.
        Ttl = 100,
        TypeOfService = 0,
    };
    TcpLayer tcpHeader = new TcpLayer
    {
        SourcePort = packet.Ethernet.IpV4.Tcp.DestinationPort,
        DestinationPort = packet.Ethernet.IpV4.Tcp.SourcePort,
        Checksum = null, // Will be filled automatically.
        SequenceNumber = seqNum = packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber,
        AcknowledgmentNumber = ackNum = packet.Ethernet.IpV4.Tcp.SequenceNumber + (uint)((packet.Ethernet.IpV4.Tcp.Payload.Length > 0) ? packet.Ethernet.IpV4.Tcp.Payload.Length : 1),
        ControlBits = tcpControlBits,
        Window = windowSize,
        UrgentPointer = 0,
        Options = TcpOptions.None,
    };
    PacketBuilder builder = new PacketBuilder(ethernetHeader, ipHeader, tcpHeader);
    return builder.Build(DateTime.Now);
}

运行效果

打开Wireshark监听"VirtualBox Host-Only Network"网卡,并设置filter为"port 8081"。

然后运行程序,通过console可以看到客户端发送的包,以及服务端返回的包,通过这些包完成了TCP连接的建立和终止。

下面是Wireshark中显示的结果,Wireshark比较友好,会显示相对seq号,所以看到的都是从0开始编号。

注意seq号和ack号的变化,[SYN]和[FIN]标志的TCP包都会消耗一个序号。

总结

本文介绍了TCP首部,通过设置TCP首部中的[SYN]标志,可以构造TCP连接建立请求包;通过设置[FIN]标志,可以构造TCP连接终止请求包。

文中使用Pcap.Net构建了一个简单的客户端,完成了向服务器建立(三次握手)和终止(四次挥手)连接的过程。

通过这个实验,一定会对TCP连接的建立和终止有一个比较直观的认识。

TCP连接的建立和终止 详解

TCP的连接和终止

TCP是一个面向连接的协议。在传输数据前必须要建立连接,在停止传输数据后要终止连接释放资源。

一.TCP连接建立

TCP连接是在IP网络中两个进程间(应用层协议)的双向、全双工的逻辑回路。由节点的IP地址和端口将连接双方对应起来。
     1.TCP连接特点:

    通过一个握手进程建立起来;
    通过一个周期性保持进程来保持,保证两个TCP节点间处于激活状态;
    通过一个握手进程来终止,释放资源。
    TCP连接也被连接中的任意一端重置。

1.TCP连接的建立

为了建立连接TCP连接双方必须从对方了解下面的信息:

    1.对方数据发送的开始序列号;
    2.对方在出站管道上发送数据的缓冲区大小;
    3.能被接收的最大段MSS;
    4.被支持的TCP选项;

通过3个TCP段的交换来了解这些信息,就是常说的TCP 握手的3个包。一般在客户端访问TCP服务器的时候,在客户端初始化一个TCP连接,服务器端打开一个特殊端口等待传入的请求。客户端主动发起第一个 SYN置位的包开始协商TCP连接。服务器接收后向客户端回ACK,最后客户端在向服务器回复ACK后连接建立。
下面我们用TCP连接的两个对等端A和B来详细介绍握手过程,其中发起方是A。

                   TCP 连接建立进程的3个TCP段交换

    段一:同步(SYN)段
    TCP连接的发起方A向B发送第一个TCP同步段(SYN).在TCP头部的选项中会包含一些选项与对端协商。
    TCP 头部包含如下字段:
    目的端口  TCP连接对端B被动打开的TCP端口数
    源端口  TCP连接发起方A主动打开的端口,大多数是一个随机一个端口。
    序列号  SYN的序列号ISN1可以看作是一个32位的计数器,由发起方A产生,具有一定的随机性。Windows 2003和XP根据派生启动(startup-derived)、2048位的随机密钥和一个基于RC4的随机数来计算ISN,从而减少下一TCP连接的 ISN被预测的可能性。
    确认号  设置为0.SYN握手第一个包的ACK字段不重要,此时刚发起连接没有数据报需要确认。但后续的ACK是重要的。
    SYN标志  置1.
    窗口  设置为默认值,指示本地TCP接收缓冲区大小的初始值。
    MSS TCP选项中的MSS   指示发起方A接收的最大的TCP段。
    选择性确认(SACK) ?TCP选项   如果包含这个字段,可以指示发起方A 的TCP能接收和解释此选项。
    窗口缩放选项   如果包含,指示出发起方A的TCP能接收和支持此选项。协商好窗口因子后此连接就固定使用直到断开连接

                            一个FTP会话的SYN段
    段二:SYN-ACK段
    在B收到SYN包后,B将发SYN-ACK,TCP选项仅包含发起方A发送的SYN包中的的选项。
    目的端口   设置为A的源端口
    源端口       设置为B端口
    序列号       B产生自己的序列号ISN2。和A发送的SYN中的ISN没有关系,仅产生的方法一样。
    确认号      期望收到的对端的下一个字节ISN1+1.
    SYN标志  置1.
    ACK标志  置1,必须有此标志,除了SYN中置0外,SYN之后的所有报文(包括SYN-ACK和实际数据包都会带ACK的标志)。
    窗口  设置B可以接收的最大窗口值,一般根据应用程序或者操作系统默认指定。
    MSS TCP选项  设为B能接收的最大长度的TCP段;
    SACK-许可       如果A发送的SYN包含此选项时才使用此选项,表示B的TCP能接收和解释SACK选项。
    窗口缩放选项   如果SYN包含,此时才会包含。

                                 一个FTP会话的SYN-ACK段
    段3:ACK段
    在TCP连接的发起方A收到SYN-ACK后,A再向B发送ACK。ACK中确认被发起方A使用的最终TCP参数,同时向B确认它该使用同样的参数。自此TCP连接建立完成。

                  一个FTP会话的SYN-ACK段

2.同时打开

两个应用程序同时执行主动建立TCP的连接的可能性是存在的,此时发送到SYN建立需要交换4个包,如图所示:

                            同时打开报文交换

需要注意的是,即使同时打开仍然只建立一条连接。(但其他的协议不一定)

3.TCP 连接的结果

    1.每一个TCP对等端知道连接上对方将被发送的第一个字节的序列号(发给对方的确认号,A发给B的确认号就是B将发送的序列号,同样B也是。)
    2.每一个TCP对等端知道连接上能发送的MSS。选取握手阶段SYN和SYN+ACK包中MSS选项中较小的值。以此值开始进行PMTU的发现机制。
    3.知道连接对端接收缓冲区大小,即窗口大小。
    4.每个对等端知道对方能否使用SACK,窗口缩放等选项。

4.Windows控制TCP建立连接进程的注册表:

TcpMaxConnectRetransmissions

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~255

Default value:2

Present by default:No

设定当试图建立一个TCP连接时,会重传多少次SYN。每次间隔时间加倍。初始的RTO为3秒,并且默认值为2,这样第一次SYN等待3秒后重传第一次,在等待6秒后重传第二次,在等待12秒没有SYN+ACK就超时了。

TcpNumConnections

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~0xFFFFFF

Default value:0xFFFFFF

Present by default:No

设定能打开的TCP最大数。默认能打开16777214(0xFFFFFF)个连接。

5.TCP半开连接

TCP 半开连接是未完成的连接建立的进程的一个TCP连接,收到一个SYN包,并且一个SYN-ACK已经发送,但是最后的ACK没有收到。前面知道XP默认设置情况下在发送2个重传SYN-ACK后等待12秒后放弃连接,并释放内存和连接的内部表项,从收到SYN到释放总共会花费21秒。

                  SYN-ACK重传输的一个半开连接

    SYN攻击

SYN攻击就是利用这种方法,使用伪装的IP地址和TCP端口,在短时间内制造大量的半开连接来耗尽资源,造成拒绝服务攻击。大量的半开连接能做如下事情:

1.使用所有可用的内存,

2.使用在TCP传输控制模块(TCB)中所有可能的项,这是一个用来跟踪TCP连接的内部表,一旦半开连接使用完所有的项,就用一个TCP连接复位来响应下一个连接企图。

3.使用所有可能的半开连接,此后用一个TCP连接复位响应下一个连接企图。

可以使用netstat -n -p tcp 查看TCP连接状态,包括半开连接。如果state出现大量的SYN-RECEIVED就该受到SYN攻击了。

Windows xp和2003 在检测和防护SYN攻击方面的注册表:

TcpMaxConnectResponseRetransmissions

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~255

Default value:2

Present by default:No

设定针对半开连接的一个AYN-ACK的重传数目,对于大于1的值使用SYN攻击防护机制。

SynAttackProtect

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~1

Default value:0

Present by default:No

设置为0禁用SYN攻击防护,1启用SYN攻击防护。被启用时,检测到SYN攻击,则半开连接的超时会更快些。

TcpMaxHalfOpen

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:100~65535

Default value:100 for windows xp 和Windows 2003 web版及标准版,500 for Windows 2003 企业版和数据中心版

Present by default:No

在SYN攻击防护起作用前,此键值设定了在SYN-RECEIVED状态中的TCP链接最大数。

TcpMaxHalfOpenRetried

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:80~65535

Default value:80 for windows xp 和Windows 2003 web版及标准版,400 for Windows 2003 企业版和数据中心版

Present by default:No

在SYN-RECEIVED状态中设定TCP连接的最大数并且在SYN攻击防护起作用前至少发送过一个重传。

6.TCP连接的维持

在建立TCP连接后,必须有一些机制维持TCP连接。如果TCP建立连接后不传输任何数据也没有应用级别的保活机制时,那么TCP连接一直存在,数天,数月会一直存在。中间的路由器可能重启,崩溃,TCP连接的双方无从知道,许多时候一个服务器希望知道客户主机是否崩溃并关机或者崩溃又重新启动。许多实现提供的保活定时器可以提供这种能力。但这个规范并不推荐,理由如下:

    在出现短暂差错的情况下,这可能会使一个非常好的连接释放掉;
    它们耗费不必要的带宽;
    在按分组计费的情况下会在互联网上花掉更多的钱。

TCP保活定时器(keepalive)

Windows 中TCP通过一个TCP keepalive的周期性交换,能维持一个TCP连接。在keepalive的TCP头部序列号字段被设为比当前出站数据流的序列号小1的值。如果一个 TCP对等端的下一个数据的字节序列号是N,那么keepalive的序列号是N-1.

在接收到keepalive包后,对等端回送一个ACK字段,并将确认号置为下一个期望收到的字节N,这个交换证实了两个对等端仍然处于TCP连接状态中。

Windows 2003 和 XP的TCP/IP在默认情况下禁用TCP的keepalive.启用情况下每2个小时发送一次keepalive。如果其他上层协议的保活机制时间小于keepalive,tcp的keepalive将不会发送。

相关注册表

KeepAliveTime

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~0xFFFFFFFF

Default value:0x6DDD00 (2小时)

Present by default:No

如果连接上没有没有数据,并且启用keepalive,此键值在每一个TCP保持活跃包之间设置了毫秒数,默认是2小时。

KeepAliveInterval

Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Data Type:REG_DWORD

Valid range:0~0xFFFFFFFF

Default value:0x3E8 (1000毫秒)

Present by default:No

在没有接收到对初始的保持活跃的响应时,此键值设置了重传时间默认是1秒。重传数目受TcpMaxDataRetransmission键值控制,默认是5.此时的重传不会有指数级的回退行为。

如果都启用且是默认,无数据传输的TCP连接在keepalive包发出后2小时6秒收不到ACK就放弃连接。

举例:

另一端崩溃

keepalive机制在重复发送探测包到一定次数后报错,由TCP转换为“连接超时”

另一端崩溃而重启

客户端telnet到服务器后,我们拔掉服务器网线重启服务器,服务器重启好后我们在telnet客户端上输入命令。服务器重启后丢失了以前连接的所有信息,此时服务器收到来着telnet客户端的命令,不知道此连接的信息,于是TCP就以复位作为应答来结束TCP连接。

另外一端不可达

拔掉网线,模拟中间路由器崩溃,keepalive探测的时候会引起ICMP差错“不可达--没有到达主机的路由”反馈给主机。

二.TCP连接的终止

TCP的连接终止需要4个包交换来完成。在两个逻辑管道上每个逻辑管道上发送方发送FIN置位的终止包,然后收到ACK后关闭该逻辑管道的连接。


              TCP连接终止的4个TCP段交换过程

段1:来自TCP对等端A的FIN-ACK

一个期望终止出站数据流的TCP对等端(A)发送一个不包含任何数据的TCP段,他具有如下特点:

    序列号,和发送带数据TCP段一样设置为出站数据的当前序列号,且当前序列号是最终序列号FSN1,因为马上要关闭了。
    确认序列号 被设为TCP对等端A期望对方发送的下一个字节。对应TCP对等端B当前序列号CSN2。
    设置ACK标志
    设置FIN标志,指示此逻辑管道上没有其他数据需要发送。

                      ftp服务器关闭FTP会话的Fin-ack段

段2:来自TCP对等端B的ACK

与SYN类似,FIN包也会占用一个字节的序列空间,并且必须把它当作是一个字节数据来确认。所以B接收到FIN-ACK后必须发送一个ACK,具有如下特点:

    序列号 设为出站数据的当前序列号CSN2
    确认号字段被设为比对端A发送的最终序列号多1的值FSN1+1.
    设置ACK标志。

               ftp服务器关闭FTP会话的Fin-ack段的ACK

一旦FIN-ACK被确认,发送初始FIN-ACK端A就不能再发送数据了,这仅终止了一个逻辑管道的连接,TCP对等端B发送数据到A的逻辑管道仍然开放,B仍然可以发数据给A。

段三:来自TCP对等端B的FIN-ACK

前面对等端A向B发送数据的逻辑管道被关闭后,如果B向A发送数据的逻辑管道仍然有数据发送,且被对等端A确认,这就是TCP半关闭。TCP对等端B向A发送数据的逻辑管道没有数据发送后,也要B向A发送FIN-ACK来关闭。

特点:

    序列号,和发送带数据TCP段一样设置为出站数据的当前序列号,且当前序列号最终序列号FSN2,因为马上要关闭了。
    确认序列号  被设为TCP对等端A期望对方发送的下一个字节。对应TCP对等端A当前序列号FSN1+1。
    设置ACK标志
    设置FIN标志,指示此逻辑管道上没有其他数据需要发送

                      ftp客户端关闭FTP会话的Fin-ack段

段四:来自TCP对等端A的ACK

同样段三的FIN-ACK包也按占用了一个字节算,并且必须作为一个字节的数据被确认。因此收到FIN-ACK的A必须发送一个ACK。

具有如下特点:

    序列号 设为出站数据的当前序列号FSN1+1
    确认号字段被设为比对端B发送的最终序列号多1的值FSN2+1
    设置ACK标志。

                      ftp客户端关闭FTP会话的Fin-ack段的ACk

当来自A的ACK被B接收后,TCP连接上的B向A发送数据的逻辑管道就会被关闭,此时经过四次握手后,整个TCP连接才会被完整关闭。

但在有些实现中段二和段段三被合并。其过程就是FIN-ACK/FIN-ACK/ACK,此时中间的FIN-ACK中的ACK是对第一个FIN-ACK的确认。

同时关闭

双方都执行主动关闭也是可能的,TCP协议也允许这样的同时关闭(simultaneous close)。双方各发送一个FIN,两个FIN经过网络传送后分别到达另一端。收到FIN后,两端发送最后的ACK。当收到最后的A C K时,关闭TCP连接.


                    同时关闭的报文段交换

TCP连接的复位(Reset)

TCP连接终止进程适用于一个TCP连接的两个管道在互相同意的情况下正常关闭。另外一种终止TCP连接的方式是通过TCP连接复位—一个具有RST(Reset)标志的TCP段来完成。

当一个不可调和的入站TCP段的TCP头中存在参数问题时,一个TCP连接复位就会被发送。例如,不恰当的源IP地址、目的IP地址或者TCP端口号都能中断一个建立了的连接。中断的TCP连接将丢失所有的TCP数据,包括正在传送中或者在等待被发送的缓冲区中。

TCP也用来拒绝一个TCP连接企图,以响应对SYN段的接收。最常见的是,SYN段中目的端口与运行在SYN段接收者上的应用层进程相对应。当达到被允许的最大值时,连接企图就会被拒绝。下图显示了TCP连接复位


                    一个显示SYN和RST段的TCP连接的复位

注意:当UDP到达一个与应用层进程不对应的目的端口时,会产生一个ICMP,目的不可达-端口不可达的报错发送给UDP数据发送方。

抓包截图显示了在一台运行FTP客户端和一台非FTP服务器主机之间的包交换。帧一是一个到FTP控制端口的SYN段,帧二是连接复位。

在连接复位段中:

1.设置了RST和ACK标志

2.序列号为0

3.确认号比SYN段的序列号多1

4.窗口大小是0.

三 TCP连接状态

TCP连接状态和说明:
状态     说明
CLOSED     不存在TCP连接
LISTEN     一个应用层协议已经发布了一个被动打开,并且有意接收TCP连接企图
SYN SENT     一个应用层协议已经发布一个主动打开,并且发送一个SYN段
SYN RCVD     一个SYN段被接收,并且一个SYN-ACK被发送
ESTABLISHED     建立TCP连接的3此握手完成。现在数据能双向传输
FIN WAIT-1     初始的关闭连接段的FIN-ACK被发送
FIN WAIT-2     响应初始的FIN-ACK的ACK被接收
CLOSING     一个FIN-ACK被接收但ACK不是针对已发送的FIN-ACK的。收到的FIN-ACK中的是针对已发送的FINA-ACK被称为同时关闭,这时两个TCP对等端在相同时刻发送FIN-ACK。
TIME WAIT     FIN- ACK已被发送并得到两个对等端的确认,并且TCP连接终止进程完成。一旦到达TIME WAIT状态,在连接的TCP端口能被重新使用前,TCP必须等待的时间是最大生存时间(MSL)的两倍。MSL是在互联网中一个TCP段能存在时间的最 大值,推荐是240秒。这个延迟防止一个使用相同端口的连接的TCP段与旧连接的TCP段的副本相混淆
CLOSE WAIT     一个FIN-ACK被接收,并且一个FIN-ACK被发送
LAST ACK     响应FIN-ACK的ACK已被接收


                          TCP状态变迁图

一个TCP对等端经过的连接状态依赖于TCP对等端是TCP连接建立的初始化方还是TCP连接终止的初始化方。


                           TCP连接图和终止图

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索服务器
, tcp
, 数据
, 进程
端口
tcp连接的建立与终止、tcp ip详解视频教程、tcp被360终止了、tcp ip详解 卷一、tcp ip详解,以便于您获取更多的相关知识。

时间: 2024-09-15 03:25:24

TCP连接建立与终止详解教程的相关文章

linux多线程编程详解教程

 这篇文章主要介绍了linux多线程编程详解教程,提供线程通过信号量实现通信的代码,大家参考使用吧 线程分类   线程按照其调度者可以分为用户级线程和核心级线程两种.   (1)用户级线程  用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定,在运行时不需要特定的内核支持.在这里,操作系统往往会提供一个用户空间的线程库,该线程库提供了线程的创建.调度.撤销等功能,而内核仍然仅对进程进行管理.如果一个进程中的某一个线程调用了一个阻塞的系统调用,那么该进程包括该进程

Photoshop耳机产品的后期质感精修效果详解教程

  这篇教程是向朋友介绍Photoshop耳机产品的后期质感精修效果过程,教程制作出来的效果很漂亮,作者主要对产品精修效果进行了详细的解析,很实用,推荐到网管之家,喜欢的朋友可以跟着教程一起来学习吧! 以上就是Photoshop耳机产品的后期质感精修效果详解教程,希望大家喜欢! 分类: PS合成图片教程 ps后期处理教程

Ajax基础详解教程(一)_AJAX相关

什么是Ajax? 在研究ajax之前首先让我们先来讨论一个问题 --什么是Web 2.0 .听到 Web 2.0 这个词的时候,应该首先问一问 "Web 1.0 是什么?" 虽然很少听人提到 Web 1.0,实际上它指的就是具有完全不同的请求和响应模型的传统 Web.比如,到 hdu.edu.cn 网站上点击一个按钮.就会对服务器发送一个请求,然后响应再返回到浏览器.该请求不仅仅是新内容和项目列表,而是另一个完整的 HTML 页面.因此当 Web 浏览器用新的 HTML 页面重绘时,可

Ajax基础详解教程(二)_AJAX相关

在上篇文章给大家介绍了Ajax基础详解教程(一),讲到Ajax中open方法的第三个参数异步和同步的问题,今天呢,就来继续往下唠,先接着上回的代码 var oBtn = document.getElementById('btn'); oBtn.onclick = function(){ var xhr = null; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject('Mic

Android开发时在模拟器之间短信的收发详解教程

本文通过运行两个Android模拟器,介绍在Android中如何实现短信服务(SMS,short message service)的功能.通过这个例子,我想带给大家的是:更加熟悉之前介绍过的Android应用程序的概念及技术细节,且通过实例调度大家的兴趣.我之所以选择SMS为例子,主要原因是SMS已经非常成熟了,从中可以发掘更多的信息和技术细节,而且我相信大部分人发短信比打电话多. 1.温故知新 广播接收者:一个广播接收者是这样一个组件,它不做什么事,仅是接受广播公告并作出相应的反应.许多广播源

Ubuntu14.04搭建Caffe(仅CPU)详解教程_Linux

首先吐槽一下本屌的笔记本,我现在的笔记本还是大一时候买的Dell INSPIRON 4010,没有Nvidia,没有Nvidia,没有Nvidia,没有Nvidia,重要的事情说四遍,呵呵. 操作系统: Ubuntu 14.04 是否使用PYTHON API: 是, 目标是安装后CAFFE能作为PYTHON MODULE来使用 硬件: 低端笔记本, 只使用CPU模式 1.安装依赖 sudo apt-get install libprotobuf-dev libleveldb-dev libsna

基于PHP+jQuery注册模块开发详解教程

/* ******* 环境: Apache2.2.8 + PHP5.2.6 + MySQL5.0.51b + jQuery-1.8.3.min.js ******* ******* 其他组件:Zend_mail( Zend_framework 1.11.11 ) ******* Date:2014-09-25 ******* Author:小dee */ 了一个简单的PHP+jQuery注册模块,需要填写的栏目包括用户名.邮箱.密码.重复密码和验证码,其中每个栏目需要具备的功能和要求如下图: 开

Android开发中原生生成JSON与解析JSON详解教程

下面分为生成JSON数据和解析JSON数据,所用的包是org.json (1)生成JSON数据方法: 比如要生成一个这样的json文本      {       "phone" : ["12345678", "87654321"],    //数组     "name" : "dream9", // 字符串        "age" : 100, // 数值       "ad

windows下安装nginx 详解教程

windows下安装nginx 详解教程 第一步 下载nginx ,windows版本,解压保存在C:/nginx下( 用的1.0.3版)    第二步 下载 php教程 fast-cgi版本(我用的是 VC9 x86 Non Thread Safe),解压到C:/php下    第三步 把C:/php/php.ini-development重命名成C:/php/php.ini,找到#cgi.fix_pathinfo=1,把#号去掉   第四步  修改C:/nginx/conf/nginx.co