更新 chat.py

This commit is contained in:
2025-12-26 14:12:54 +08:00
parent c8cfb92871
commit a2c73d3c3c

58
chat.py
View File

@@ -1,60 +1,87 @@
import socket import socket
import threading import threading
import protocol import protocol
import sys
LOCAL_PORT = 9000 LOCAL_PORT = 9000
TIMEOUT = 2 TIMEOUT = 2 # 秒
class StopWaitChat: class StopWaitChat:
def __init__(self, local_port, peer_addr): def __init__(self, local_port, peer_addr):
self.sock = socket.socket( # IPv6 UDP socket
socket.AF_INET6, self.sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
socket.SOCK_DGRAM
) # 绑定本地 IPv6 任意地址
self.sock.bind(("::", local_port)) self.sock.bind(("::", local_port))
# 设置 socket 超时(用于停等协议)
self.sock.settimeout(TIMEOUT) self.sock.settimeout(TIMEOUT)
self.peer_addr = peer_addr self.peer_addr = peer_addr
# 停等协议序号
self.send_seq = 0 self.send_seq = 0
self.recv_seq = 0 self.recv_seq = 0
def sender(self): def sender(self):
"""
发送线程(停等协议)
"""
while True: while True:
try:
msg = input(">> ").encode() msg = input(">> ").encode()
except EOFError:
break
pkt = protocol.make_packet( pkt = protocol.make_packet(
self.send_seq, self.send_seq,
protocol.TYPE_DATA, protocol.TYPE_DATA,
msg msg
) )
# 停等:一直发,直到收到正确 ACK
while True: while True:
self.sock.sendto(pkt, self.peer_addr) self.sock.sendto(pkt, self.peer_addr)
try: try:
data, _ = self.sock.recvfrom(1024) data, _ = self.sock.recvfrom(1024)
seq, ptype, _ = protocol.parse_packet(data) seq, ptype, _ = protocol.parse_packet(data)
if ptype == protocol.TYPE_ACK and seq == self.send_seq: if ptype == protocol.TYPE_ACK and seq == self.send_seq:
# 正确 ACK
self.send_seq ^= 1 self.send_seq ^= 1
break break
except socket.timeout: except socket.timeout:
print("[timeout] retransmit") print("[timeout] retransmit")
def receiver(self): def receiver(self):
"""
接收线程(必须捕获 timeout
"""
while True: while True:
try:
data, addr = self.sock.recvfrom(1024) data, addr = self.sock.recvfrom(1024)
except socket.timeout:
continue
seq, ptype, payload = protocol.parse_packet(data) seq, ptype, payload = protocol.parse_packet(data)
if ptype == protocol.TYPE_DATA: if ptype == protocol.TYPE_DATA:
if seq == self.recv_seq: if seq == self.recv_seq:
print("\npeer:", payload.decode()) print("\npeer:", payload.decode())
self.recv_seq ^= 1 self.recv_seq ^= 1
# 无论是否重复,都返回 ACK
ack = protocol.make_packet(seq, protocol.TYPE_ACK) ack = protocol.make_packet(seq, protocol.TYPE_ACK)
self.sock.sendto(ack, addr) self.sock.sendto(ack, addr)
if __name__ == "__main__":
import sys def main():
if len(sys.argv) != 3: if len(sys.argv) != 3:
print("用法: python3 chat.py <对方IPv6地址> <对方端口>") print("用法: python3 chat.py <对方IPv6地址或域名> <对方端口>")
exit(1) sys.exit(1)
peer_ip = sys.argv[1] peer_ip = sys.argv[1]
peer_port = int(sys.argv[2]) peer_port = int(sys.argv[2])
@@ -64,5 +91,16 @@ if __name__ == "__main__":
(peer_ip, peer_port) (peer_ip, peer_port)
) )
threading.Thread(target=chat.receiver, daemon=True).start() # 启动接收线程
recv_thread = threading.Thread(
target=chat.receiver,
daemon=True
)
recv_thread.start()
# 主线程负责发送
chat.sender() chat.sender()
if __name__ == "__main__":
main()