动手学习TCP系列之客户端状态变迁(1)(2)
private static void PacketHandler(PacketCommunicator communicator, EndPointInfo endPointInfo, bool clientToSendFin = true) { 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): if (tcpStatus == TCPStatus.SYN_SEND) { Utils.PacketInfoPrinter(packet); Packet ack = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment); communicator.SendPacket(ack); tcpStatus = TCPStatus.ESTABLISHED; } break; case (TcpControlBits.Fin | TcpControlBits.Acknowledgment): if (tcpStatus == TCPStatus.FIN_WAIT_2) { Utils.PacketInfoPrinter(packet); Packet ack = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment); communicator.SendPacket(ack); tcpStatus = TCPStatus.TIME_WAIT; } else if (tcpStatus == TCPStatus.ESTABLISHED) { Utils.PacketInfoPrinter(packet); Packet ack = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment); communicator.SendPacket(ack); tcpStatus = TCPStatus.CLOSE_WAIT; } break; case TcpControlBits.Acknowledgment: if (tcpStatus == TCPStatus.FIN_WAIT_1) { tcpStatus = TCPStatus.FIN_WAIT_2; Utils.PacketInfoPrinter(packet, tcpStatus); } else if (tcpStatus == TCPStatus.LAST_ACK) { tcpStatus = TCPStatus.CLOSED; Utils.PacketInfoPrinter(packet, tcpStatus); running = false; } break; default: Utils.PacketInfoPrinter(packet); break; } } else { switch (packet.Ethernet.IpV4.Tcp.ControlBits) { case TcpControlBits.Synchronize: if (tcpStatus == TCPStatus.SYN_SEND) { Utils.PacketInfoPrinter(packet, tcpStatus); } break; case TcpControlBits.Acknowledgment: if (tcpStatus == TCPStatus.ESTABLISHED) { Utils.PacketInfoPrinter(packet, tcpStatus); if (clientToSendFin) running = false; } else if (tcpStatus == TCPStatus.TIME_WAIT) { Utils.PacketInfoPrinter(packet, tcpStatus); running = false; } else if (tcpStatus == TCPStatus.CLOSE_WAIT) { Utils.PacketInfoPrinter(packet, tcpStatus); Packet fin = Utils.BuildTcpPacket(endPointInfo, TcpControlBits.Fin | TcpControlBits.Acknowledgment); communicator.SendPacket(fin); tcpStatus = TCPStatus.LAST_ACK; } break; case (TcpControlBits.Fin | TcpControlBits.Acknowledgment): if (tcpStatus == TCPStatus.FIN_WAIT_1) { Utils.PacketInfoPrinter(packet, tcpStatus); } else if (tcpStatus == TCPStatus.LAST_ACK) { Utils.PacketInfoPrinter(packet, tcpStatus); } break; default: Utils.PacketInfoPrinter(packet); break; } } break; default: throw new InvalidOperationException("The result " + result + " should never be reached here"); } } while (running); }
运行效果
下面,将"clientToSendFin"设置为"true",看看正常情况下客户端的状态变迁。
打开Wireshark监听"VirtualBox Host-Only Network"网卡,并设置filter为"port 8081"。
运行程序,通过console可以看到客户端和服务端之间的包,以及客户端的状态变迁。
下面是Wireshark抓到的包,这七个数据包就表示了TCP连接的建立和终止过程。
总结
本文介绍了TCP状态变迁图,根据客户端的状态变迁过程,得到了客户端的状态变迁表。
然后使用Pcap.Net,基于客户端的状态变迁表,构建了一个简单的客户端,展示了客户端状态变迁的过程。
通过这个实验,一定能够对TCP客户端的状态变迁有个深刻的印象。
评论暂时关闭