如果我在TCP通信中丢失了数据包,我该如何重新连接我的客户端到我的服务器?

2024-09-29 23:20:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用两台不同的计算机(两个不同的IP)在服务器和客户机之间创建通信,但是当我在向服务器发送数据包的过程中丢失数据包时,我的客户机无法重新连接到服务器,因此它停止发送数据包。你知道吗

我试过用另一个插座连接(服务器地址)但即使这样也不起作用。你知道吗

这是我的代码(在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()

我无法重新连接我的客户端到服务器时,它失去了一个数据包,有没有另一种方法来重新连接而不失去连接?你知道吗

如果有人能帮我,我真的需要一只手。。。你知道吗

谢谢。你知道吗


Tags: ipiddataifservertimepacketaddress
1条回答
网友
1楼 · 发布于 2024-09-29 23:20:38

如@user207421所述,由于您仍在使用TCP连接,您通常不必自己处理传输错误,因为无错误数据传输是针对UDP的key features of TCP之一。你知道吗

此外,我建议使用^{}Python模块构建某种客户机/服务器应用程序。它为连接建立和管理以及线程管理节省了许多样板代码。你知道吗

最后,只有当服务器在sock.accept()方法中时,您才能连接到它。我担心当您失去连接时,服务器会被任何connection.recv()connection.sendall()函数阻塞,因此不接受任何新连接;这就是为什么我们经常将服务器工作负载委托给其他线程或进程的原因;socketserver文档:

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 and ThreadingMixIn mix-in classes can be used to support asynchronous behaviour.

所以,总结一下我的答案: 你正在经历一种你不打算遇到的行为。这可能是一个错误概念的症状。所以使用可用的工具来解决这个问题。你知道吗

相关问题 更多 >

    热门问题