-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient_scenario2.py
More file actions
168 lines (148 loc) · 7.21 KB
/
client_scenario2.py
File metadata and controls
168 lines (148 loc) · 7.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# client_scenario2.py
# این کلاینت برای نمایش بازارسال بسته پس از تایماوت طراحی شده است.
# این کار با "از دست دادن" (عدم ارسال) اولین بسته داده به صورت عمدی انجام میشود.
import socket
import random
import threading
import time
from packet import TCPPacket
# --- تنظیمات ---
SERVER_HOST = '127.0.0.1'
SERVER_PORT = 12345
TIMEOUT_SECONDS = 5
MSS = 100
WINDOW_SIZE = 5
# زمان تایماوت را کمی کوتاهتر میکنیم تا سناریو سریعتر نمایش داده شود
RETRANSMISSION_TIMEOUT = 2
# --- متغیرهای سراسری و توابع کمکی (بدون تغییر) ---
window_lock = threading.Lock()
base = 0
next_seq_num = 0
in_flight_packets = {}
retransmission_timer = None
program_active = True
def resend_oldest_packet(sock, dest_addr):
with window_lock:
if not in_flight_packets: return
oldest_seq = base
if oldest_seq in in_flight_packets:
packet, _ = in_flight_packets[oldest_seq]
# این بار بسته واقعا ارسال میشود
sock.sendto(packet.to_bytes(), dest_addr)
# لاگ کلیدی برای نمایش بازارسال
print(f"--> [RETRANSMISSION] Timeout occurred! Resending packet with seq={oldest_seq}")
in_flight_packets[oldest_seq] = (packet, time.time())
# ریست کردن تایمر برای تلاش بعدی
start_timer(sock, dest_addr)
def start_timer(sock, dest_addr):
global retransmission_timer
if retransmission_timer: retransmission_timer.cancel()
retransmission_timer = threading.Timer(RETRANSMISSION_TIMEOUT, resend_oldest_packet, args=[sock, dest_addr])
retransmission_timer.start()
def stop_timer():
global retransmission_timer
if retransmission_timer: retransmission_timer.cancel()
retransmission_timer = None
def receiver_thread(sock):
global base
print("[Receiver Thread] Started.")
while program_active:
try:
sock.settimeout(1.0)
packet_bytes, _ = sock.recvfrom(4096)
packet = TCPPacket.from_bytes(packet_bytes)
if packet.flags['ACK']:
with window_lock:
if packet.ack_num > base:
print(f"[Receiver Thread] Received ACK, moving window base to {packet.ack_num}")
base = packet.ack_num
acked_seqs = [seq for seq in in_flight_packets if seq < base]
for seq in acked_seqs: del in_flight_packets[seq]
if in_flight_packets: start_timer(sock, (SERVER_HOST, SERVER_PORT))
else: stop_timer()
except socket.timeout: continue
except Exception: break
print("[Receiver Thread] Stopped.")
def main():
global base, next_seq_num, program_active
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# --- فاز ۱: Handshake با لاگ دقیق ---
print("\n[Client - Handshake]")
# ... (کد Handshake با لاگ دقیق)
client_seq = random.randint(10001, 20000)
syn_packet = TCPPacket(src_port=0, dest_port=SERVER_PORT, seq_num=client_seq, ack_num=0, syn=1)
client_socket.sendto(syn_packet.to_bytes(), (SERVER_HOST, SERVER_PORT))
client_port = client_socket.getsockname()[1]
syn_packet.src_port = client_port
print(f"1. Sent SYN: {syn_packet}")
client_socket.settimeout(TIMEOUT_SECONDS)
syn_ack_data, _ = client_socket.recvfrom(4096)
syn_ack_packet = TCPPacket.from_bytes(syn_ack_data)
print(f"2. Received SYN-ACK: {syn_ack_packet}")
client_ack = syn_ack_packet.seq_num + 1
client_seq += 1
ack_packet = TCPPacket(src_port=client_port, dest_port=SERVER_PORT, seq_num=client_seq, ack_num=client_ack, ack=1)
client_socket.sendto(ack_packet.to_bytes(), (SERVER_HOST, SERVER_PORT))
print(f"3. Sent Final ACK: {ack_packet}")
print("Connection Established.")
base = client_seq
next_seq_num = client_seq
# --- فاز ۲: انتقال داده برای نمایش بازارسال ---
print("\n[Phase 2: Data Transfer - Retransmission Scenario]")
receiver = threading.Thread(target=receiver_thread, args=(client_socket,))
receiver.start()
message = "A short message."
data_to_send = message.encode('utf-8')
total_len = len(data_to_send)
# *** منطق سناریو ***
# ساخت بسته اول
segment = data_to_send
data_packet = TCPPacket(src_port=client_port, dest_port=SERVER_PORT, seq_num=next_seq_num, ack_num=client_ack, payload=segment)
# شبیهسازی از دست رفتن بسته اول
print(f"!!! SCENARIO 2: SIMULATING PACKET LOSS. NOT SENDING packet with seq={next_seq_num} !!!")
# ما بسته را به بافر اضافه کرده و تایمر را فعال میکنیم، گویی که ارسال شده است
with window_lock:
in_flight_packets[next_seq_num] = (data_packet, time.time())
start_timer(client_socket, (SERVER_HOST, SERVER_PORT))
next_seq_num += len(segment)
# منتظر میمانیم تا تایمر فعال شود و بازارسال اتفاق بیفتد
while in_flight_packets:
print("Client waiting for retransmission timer to expire...")
time.sleep(1)
print("\nPacket was successfully retransmitted and acknowledged.")
# --- فاز ۳: پایان اتصال با لاگ دقیق ---
program_active = False
receiver.join()
print("\n[Phase 3: Connection Termination]")
# ... (کد پایان اتصال با لاگ دقیق)
try:
fin_packet = TCPPacket(src_port=client_port, dest_port=SERVER_PORT, seq_num=next_seq_num, ack_num=0, fin=1)
client_socket.sendto(fin_packet.to_bytes(), (SERVER_HOST, SERVER_PORT))
print(f"Client: Sent FIN packet: {fin_packet}")
got_ack_for_my_fin = False
got_fin_from_server = False
server_fin_seq_num = -1
client_socket.settimeout(TIMEOUT_SECONDS)
while not (got_ack_for_my_fin and got_fin_from_server):
packet_bytes, _ = client_socket.recvfrom(4096)
packet = TCPPacket.from_bytes(packet_bytes)
if packet.flags['ACK'] and packet.ack_num == next_seq_num + 1:
got_ack_for_my_fin = True
print(f"Client: Received ACK for its FIN: {packet}")
if packet.flags['FIN']:
got_fin_from_server = True
server_fin_seq_num = packet.seq_num
print(f"Client: Received FIN from server: {packet}")
final_ack_num = server_fin_seq_num + 1
final_ack_packet = TCPPacket(src_port=client_port, dest_port=SERVER_PORT, seq_num=next_seq_num + 1, ack_num=final_ack_num, ack=1)
client_socket.sendto(final_ack_packet.to_bytes(), (SERVER_HOST, SERVER_PORT))
print(f"Client: Sent final ACK: {final_ack_packet}")
print("Connection terminated successfully.")
except socket.timeout:
print("Client: Timeout during connection termination.")
finally:
print("Shutting down...")
client_socket.close()
print("Client is shut down.")
if __name__ == "__main__":
main()