我正在使用两台不同的计算机(两个不同的IP)在服务器和客户端之间建立通信,但是当我在将数据包发送到服务器的过程中丢失数据包时,我的客户端无法重新连接到服务器,因此它停止发送数据包。
我试图使用另一个sock.connect(server_address),但即使这样也无法正常工作。
这是我的代码(在堆栈溢出中有一个有用的程序员的结构提示):
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()
当客户端丢失数据包时,我无法将其重新连接到服务器,是否有另一种方法可以重新连接它们而不丢失连接?
如果有人可以帮助我,我真的可以伸出援手...
谢谢。
答案 0 :(得分:2)
如@ user207421所述,由于您仍在使用TCP连接,因此通常不必自己处理传输错误,因为无错误的数据传输是针对UDP的key features of TCP之一。
此外,我建议使用socketserver
Python模块来构建某种客户端/服务器应用程序。它将您从许多用于连接建立和管理以及线程管理的样板代码中节省下来。
最后,只有当服务器处于sock.accept()
方法中时,才能连接到服务器。我担心当您断开连接时,服务器将无法使用connection.recv()
或connection.sendall()
函数中的任何一个,从而不接受任何新的连接;这就是为什么我们经常将服务器工作负载委派给其他线程或进程;来自socketserver
文档:
这四个类同步处理请求 ;必须先完成每个请求,然后才能开始下一个请求。如果每个请求都需要很长时间才能完成,这是不合适的,因为它需要大量的计算,或者因为它返回了很多客户端处理缓慢的数据。解决方案是创建一个单独的进程或线程来处理每个请求。
ForkingMixIn
和ThreadingMixIn
混合类可用于支持异步行为。
因此,总结一下我的答案: 您正在经历您不打算遇到的行为。这可能是误解的症状。因此,请使用可用的工具来解决此问题。