一次握手的轨迹
本节的内存版 TCP 状态机(判题机不联网;真机上 ss -tan 看到的 State 就是这些名字):
TABLE[(状态, 事件)] = (新状态, 要发出去的段) 事件:listen / connect / close / timeout / retrans 是本机动作,SYN / SYN-ACK / ACK / FIN / RST 是收到的段
talk(script, drop=()) script 形如 ["B:listen", "A:connect", "A:close", "B:close"];一台主机发出的段立刻送到对面(序号在 drop 里的丢掉,轨迹里标 x),对面的回信再送回来
交回 (轨迹 ["A>B SYN", "B>A SYN-ACK", ...], {"A": 状态, "B": 状态})B 先 listen,A 再 connect。打印段的轨迹、段数、两边的最终状态:
TABLE = {
("CLOSED", "listen"): ("LISTEN", None),
("CLOSED", "connect"): ("SYN-SENT", "SYN"),
("LISTEN", "SYN"): ("SYN-RECV", "SYN-ACK"),
("SYN-SENT", "SYN-ACK"): ("ESTAB", "ACK"),
("SYN-RECV", "ACK"): ("ESTAB", None),
("ESTAB", "close"): ("FIN-WAIT-1", "FIN"),
("ESTAB", "FIN"): ("CLOSE-WAIT", "ACK"),
("FIN-WAIT-1", "ACK"): ("FIN-WAIT-2", None),
("FIN-WAIT-1", "FIN"): ("CLOSING", "ACK"),
("FIN-WAIT-2", "FIN"): ("TIME-WAIT", "ACK"),
("CLOSING", "ACK"): ("TIME-WAIT", None),
("CLOSE-WAIT", "close"): ("LAST-ACK", "FIN"),
("LAST-ACK", "ACK"): ("CLOSED", None),
("LAST-ACK", "retrans"): ("LAST-ACK", "FIN"),
("TIME-WAIT", "FIN"): ("TIME-WAIT", "ACK"),
("TIME-WAIT", "timeout"): ("CLOSED", None),
("CLOSED", "FIN"): ("CLOSED", "RST"),
("LAST-ACK", "RST"): ("CLOSED", None),
}
class Host:
def __init__(self, name):
self.name = name
self.state = "CLOSED"
def step(self, event):
"""交回要发出去的段(没有就 None);没这一行的 (状态, 事件) 一律不动。"""
key = (self.state, event)
if key not in TABLE:
return None
self.state, out = TABLE[key]
return out
def talk(script, drop=()):
"""script: ["B:listen", "A:connect", "A:close", "B:close", "A:timeout", ...]。
一台主机发出的段立刻送到对面(除非它的序号在 drop 里),对面的回信再送回来。
交回 (段的轨迹 ["A>B SYN", ...], {"A": 状态, "B": 状态})。"""
hosts = {"A": Host("A"), "B": Host("B")}
trace = []
def send(frm, seg):
to = "B" if frm == "A" else "A"
trace.append(frm + ">" + to + " " + seg)
if len(trace) in drop:
trace[-1] += " x"
return
reply = hosts[to].step(seg)
if reply:
send(to, reply)
for item in script:
who, event = item.split(":")
seg = hosts[who].step(event)
if seg:
send(who, seg)
return trace, {k: h.state for k, h in hosts.items()}
trace, st = talk(["B:listen", "A:connect"])
print(",".join(s.split()[1] for s in trace) + "/" + str(len(trace)) + "/" + st["A"] + "," + st["B"])
全部评论