动手学习TCP系列之服务端状态变迁(1)
动手学习TCP系列之服务端状态变迁(1)
上一篇文章介绍了TCP状态机,并且通过实验了解了TCP客户端正常的状态变迁过程。
那么,本篇文章就一起看看TCP服务端的正常状态变迁过程。
服务端状态变迁
根据上一篇文章中的TCP状态变迁图,可以得到服务器的正常状态变迁流程如下:
CLOSED -> LISTEN -> SYN_RECV -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
服务端状态变迁实验
下面就结合上面分析出来的服务端状态变迁表,利用Pcap.Net来模拟服务端正常的状态变迁过程。
代码实现
跟前面几次正好相反,这次我们将在宿主机运行Pcap.Net实现的服务端,然后在虚拟机运行一个客户端。
对于服务端,主程序中设置了源和目的端的连接信息,这次宿主机中的服务端将监听“3333”端口。
然后,程序中设置了服务端TCP初始状态为"LISTENING",然后就直接运行监听函数了。
// Open the output device using (PacketCommunicator communicator = selectedDevice.Open(System.Int32.MaxValue, // name of the device PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode 1)) // read timeout { EndPointInfo endPointInfo = new EndPointInfo();
endPointInfo.SourceMac = "08:00:27:00:C0:D5";
endPointInfo.DestinationMac = "";
endPointInfo.SourceIp = "192.168.56.101";
endPointInfo.DestinationIp = "";
endPointInfo.SourcePort = 3333;
endPointInfo.DestinationPort = 0;
using (BerkeleyPacketFilter filter = communicator.CreateFilter("tcp port " + endPointInfo.SourcePort))
{
// Set the filter
communicator.SetFilter(filter);
}
tcpStatus = TCPStatus.LISTENING;
PacketHandler(communicator, endPointInf)
}
这次的监听函数"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: if (tcpStatus == TCPStatus.LISTENING) { endPointInfo.DestinationMac = packet.Ethernet.Source.ToString(); endPointInfo.DestinationIp = packet.Ethernet.IpV4.Source.ToString(); endPointInfo.DestinationPort = packet.Ethernet.IpV4.Tcp.SourcePort; Utils.PacketInfoPrinter(packet); Packet synAck = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Synchronize | TcpControlBits.Acknowledgment); communicator.SendPacket(synAck); tcpStatus = TCPStatus.SYN_RECEIVED; }break; case TcpControlBits.Acknowledgment: if (tcpStatus == TCPStatus.SYN_RECEIVED) { tcpStatus = TCPStatus.ESTABLISHED; Utils.PacketInfoPrinter(packet, tcpStatus); } else if (tcpStatus == TCPStatus.LAST_ACK) { tcpStatus = TCPStatus.CLOSED; Utils.PacketInfoPrinter(packet, tcpStatus); tcpStatus = TCPStatus.LISTENING; } else if (tcpStatus == TCPStatus.FIN_WAIT_1) { tcpStatus = TCPStatus.FIN_WAIT_2; Utils.PacketInfoPrinter(packet); } 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; default: Utils.PacketInfoPrinter(packet); break; } } else { switch (packet.Ethernet.IpV4.Tcp.ControlBits) { case (TcpControlBits.Synchronize | TcpControlBits.Acknowledgment): if (tcpStatus == TCPStatus.SYN_RECEIVED) { Utils.PacketInfoPrinter(packet, tcpStatus); }
评论暂时关闭