Reputation: 103
I am creating a communication between a server and a client using two different computers (two different IPs), but when I am losing a packet in the middle of the process of sending them to the server, my client is not able to reconnect to the server, so it stops sending packets.
I have tried to use another sock.connect(server_address) but even with that it didn't work.
This is my code (with structure tips from a helpful programmer here in Stack Overflow):
import socket
import threading
import time
class Server(threading.Thread):
def run(self) -> None:
MY_IP = "10.0.0.113" # Other computer running this class
PORT_NUMBER = 13000
# socket TCP/IP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (MY_IP, PORT_NUMBER)
print('Server starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
sock.listen(1)
while True:
print('Waiting a connection')
connection, client_address = sock.accept()
try:
print('Connection from ', client_address)
while True:
data = connection.recv(16)
#print('received {!r}'.format(data))
if data:
#print('sending data back to the client')
connection.sendall(data)
else:
print('no data came from ', client_address)
break
finally:
connection.close()
class Client(threading.Thread):
def run(self) -> None:
#MY_IP = "10.0.0.112" won't be used because it will send to the server IP.
OTHER_IP = "10.0.0.113"
PORT_NUMBER = 13000
g_windowTime = 0
# socket TCP/IP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (OTHER_IP, PORT_NUMBER)
sock.connect(server_address)
def execute():
global g_windowTime
g_windowTime = time.time()
sizeWindow = 1
id_packet = "1"
packets_resend = []
while True:
packets_sent = []
# Send data
sizeWindow, packets_sent, id_packet = send_packets(sizeWindow, packets_sent, packets_resend, id_packet)
print(f"Send packet returned: {sizeWindow}")
# Waits for the amount
amount_received = 0
amount_expected = len(packets_sent)
while amount_received < amount_expected:
try:
sock.settimeout(5.0)
data = sock.recv(16)
amount_received += len(data)
except:
print("The packet needs to be resend")
print(f"execute: {sizeWindow} -> {sizeWindow*2}")
sizeWindow = sizeWindow * 2
currentTime = (time.time() - g_windowTime) * 1000
print(f'{str(round(currentTime, 2)).replace(".", ",")}; {int(sizeWindow)}')
if currentTime > 10000:
exit()
def send_packets(sizeWindow, packets_sent, packets_resend, id_packet):
global g_windowTime
i = 0
j = 0
timer = 0
while i < sizeWindow:
if packets_resend == []:
packet = id_packet.encode('utf-8')
id_packet = str(int(id_packet) + 1)
elif packets_resend != []:
packet = packets_resend.pop(0)
if packet not in packets_sent:
packets_sent.append(packet)
# Send the packet
try:
sock.sendall(packet)
except:
# Here is the problem, it cannot connect to the server if it looses a packet
connected = False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while not connected:
try:
print("Problem with sendall")
connect()
connected = True
print('re-connection successful')
except socket.error:
time.sleep(2)
# Timer
if (i == 0):
timer = time.time()
elif (i > 0) and (time.time() > (timer + 0.01)):
if sizeWindow > 1:
j = i + 1
while j < sizeWindow:
packet = id_packet.encode('utf-8')
id_packet = str(int(id_packet) + 1)
packets_resend.append(packet)
j += 1
print(f"send packets: {sizeWindow} -> {sizeWindow/2}")
sizeWindow = sizeWindow / 2
currentTime = (time.time() - g_windowTime) * 1000
print(f'{str(round(currentTime, 2)).replace(".", ",")}; {int(sizeWindow)}')
send_packets(sizeWindow, packets_sent, packets_resend, id_packet)
i += 1
return sizeWindow, packets_sent, id_packet
def connect():
sock.connect(server_address)
execute()
sock.close()
if __name__ == '__main__':
#server = Server() needs to be executed in another computer to see the problem, in the same computer it works fine
#server.start()
time.sleep(1)
client = Client()
client.start()
I am not able to reconnect my client to the server when it looses a packet, is there another method to reconnect them without loosing the connection?
If anyone could help me with that I really could use a hand...
Thanks.
Upvotes: 1
Views: 371
Reputation: 3109
As stated by @user207421, as you are still using a TCP connection you normally do not have to handle transmission error yourself, as error-free data transfert is one of the key features of TCP against UDP.
Moreover, I would recommend to use the socketserver
Python module to build some kind of client/server application. It saves you from many boilerplate code for connection establishment and management as well as thread management.
Finally, your can connect to a server only when it is in the sock.accept()
method. I fear that when you lose your connection the server is blocked in any of connection.recv()
or connection.sendall()
function, thus not accepting any new connection ; that's why we often delegate server workload to other threads or processes ; from the socketserver
documentation:
These four classes process requests synchronously; each request must be completed before the next request can be started. This isn’t suitable if each request takes a long time to complete, because it requires a lot of computation, or because it returns a lot of data which the client is slow to process. The solution is to create a separate process or thread to handle each request; the
ForkingMixIn
andThreadingMixIn
mix-in classes can be used to support asynchronous behaviour.
So, to sum-up my answer: You are experiencing a behavior that you aren't intended to encounter. This is probably the symptom of a mis-conception. So use the available tools to fix this.
Upvotes: 2