-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSenderSR.py
106 lines (90 loc) · 4.22 KB
/
SenderSR.py
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
from Statistics import Statistics
from DataPacket import DataPacket
from ResponsePacket import ResponsePacket
from FileReading import FileReader
from CommunicationSettings import CommunicationSettings
from threading import Thread
#Selective repeat sender
class SenderSR:
def __init__(self, name: str, stats: Statistics) -> None:
self.name = name
self.thread = None # Thread that this terminal will run on
self.recieved_packets = [] # List of the packages that this terminal recieved
self.packages_to_send = [] # List of the packages to send
self.simulate = False
self.reciever = None
self.stats = stats
self.start_packet = False
#Bind the sender and the reciever
def bind(self, reciever) -> None:
self.reciever = reciever
#Creates the packages to send
def create_packages(self, file_name: str) -> None:
byte_list = FileReader.read_file(file_name, CommunicationSettings.data_bytes)
for index, data in enumerate(byte_list): # Convert words to packages
self.packages_to_send.append(DataPacket(index % CommunicationSettings.window_size, data))
#Create an end of transmition packet and add it to the end of the queue
end_packet = DataPacket()
end_packet.mark_as_eot()
self.packages_to_send.append(end_packet)
self.stats.min_packages = len(self.packages_to_send) + (len(self.packages_to_send) - 1) // 5
if CommunicationSettings.logging:
print(f"Created {len(self.packages_to_send)} packages")
#Starts the transmition
def send_image(self, image_name: str) -> None:
self.create_packages(image_name) # Create the packages from the file
#To start the transmition make a response packet that asks for retransmition
startPacket = ResponsePacket()
startPacket.mark_as_retransmit()
startPacket.set_max_key()
self.recieve_packet(startPacket)
if CommunicationSettings.logging:
print(f"{self.name}: Data transmition started")
#Creates and starts the terminal thread
def start(self) -> None:
self.simulate = True
self.thread = Thread(target=self.run)
self.thread.start()
#Adds the packet to the recieved packet list
def recieve_packet(self, packet) -> None:
self.recieved_packets.append(packet)
self.stats.ammount_of_packets += 1
#Runs the thread loop
def run(self) -> None:
while self.simulate:
if not self.recieved_packets:
continue
self.handle_packets()
#Determines what to do with the packet
def handle_packets(self) -> None:
packet: ResponsePacket = self.recieved_packets.pop(0)
#Scramble the packet
message = packet.to_binary()
if self.start_packet:
message = CommunicationSettings.scramble_message(message)
self.start_packet = True
response_packet = ResponsePacket()
response_packet.to_packet(message)
if response_packet.get_valid():
# If no retransmition is needed then remove the current window of packets from the queue
if response_packet.should_retransmit() == False:
del self.packages_to_send[0:CommunicationSettings.window_size]
if len(self.packages_to_send) == 0:
self.simulate = False # Every packet was send succesfuly
return
#If the content isn't the same then the error wasn't detected
if message != response_packet.to_binary():
self.stats.undetected_errors += 1
if response_packet.is_max_key():
#Send new window
for i in range(min(CommunicationSettings.window_size, len(self.packages_to_send))):
self.reciever.recieve_packet(self.packages_to_send[i])
else:
#Resend the requested packet
self.reciever.recieve_packet(self.packages_to_send[response_packet.get_key()])
else:
#Ask for the retransmition of the response
self.stats.detected_errors += 1
response = ResponsePacket()
response.mark_as_retransmit()
self.reciever.recieve_packet(response)