【问题标题】:I cannot find my logic or syntax error in my Python TCP program我在 Python TCP 程序中找不到我的逻辑或语法错误
【发布时间】:2019-11-27 08:18:38
【问题描述】:

我正在创建一个 TCP 服务器 x 客户端通信,但我遇到了一个逻辑问题,我无法找出它发生的原因。我的 sizeWindow 的值以某种方式获取了以前的值并打破了我的窗口的大小......

如您所见:

我需要找出为什么它从 256 变为 1024,它应该变为 512 但它不是......

我的猜测是它没有更新 sizeWindow 值,但我不知道为什么。

要测试我的项目,您将需要 Server 和 Client 类:

服务器类(你应该先运行这个类):

# ServerTCP
import socket

MY_IP = "127.0.0.1"
PORT_NUMBER = 13000


# socket TCP/IP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


server_address = (MY_IP, PORT_NUMBER)
print('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()

这是我的客户端类(问题出在哪里......):

# ClientTCP - 4.0

import socket
import time

MY_IP = "127.0.0.1"
PORT_NUMBER = 13000

g_windowTime = 0

# socket TCP/IP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = (MY_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)

        # 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")
        sizeWindow = sizeWindow * 2
        tempo = (time.time() - g_windowTime) * 1000
        print(f'{str(round(tempo, 2)).replace(".", ",")}; {int(sizeWindow)}')
        if tempo > 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:
            print("Problem with sendall")
            connect()

        # 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
                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()

我最好的猜测是问题出在方法 send_packetsreturn sizeWindow, packets_sent, id_packet 中,它返回 3 次...,2 次返回 sizeWindow 的正确值,但不知何故第三次它改变了 sizeWindow 的值到以前的值,在我的算法中创造了一个很大的问题......

我不知道是我忘记了什么还是语法错误,但我找不到它发生的原因......

如果有人能尝试找出它发生的原因,我会非常高兴。

非常感谢。

【问题讨论】:

  • 乍一看,我没有看到send_packets方法有什么问题。但是我想你会遇到time.time() &gt; (timer + 0.01)False 的情况,因此不会执行你的sizeWindow = sizeWindow / 2。我会尝试更深入地调查。
  • 是的,就是这样,它忽略了if(它应该这样做)并使用return sizeWindow, packets_sent, id_packet。它进入方法send_packets 三次,但最后一次返回sizeWindow 作为前一次。

标签: python python-3.x


【解决方案1】:

我发现了你的错误。在send_packets 中,您有一个递归调用,您不会从中获得返回的sizeWindow。 你应该更新你的函数:

def send_packets(sizeWindow, packets_sent, packets_resend, id_packet):
    # [...]
    while i < sizeWindow:
        # [...]
        # Timer
        if (i == 0):
            timer = time.time()
        elif (i > 0) and (time.time() > (timer + 0.01)):
            if sizeWindow > 1:
                [...]
                sizeWindow, packets_sent, id_packet = send_packets(sizeWindow, packets_sent, packets_resend, id_packet)

        i += 1

    return sizeWindow, packets_sent, id_packet

下面是我用来调试你的错误的代码。

import socket
import threading
import time


class Server(threading.Thread):

    def run(self) -> None:
        MY_IP = "127.0.0.1"
        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 = "127.0.0.1"
        PORT_NUMBER = 13000

        g_windowTime = 0

        # socket TCP/IP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        server_address = (MY_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
                tempo = (time.time() - g_windowTime) * 1000
                print(f'{str(round(tempo, 2)).replace(".", ",")}; {int(sizeWindow)}')
                if tempo > 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:
                    print("Problem with sendall")
                    connect()

                # 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()
    server.start()
    time.sleep(1)

    client = Client()
    client.start()

这是相关的输出:

Server starting up on 127.0.0.1 port 13000
Waiting a connection
Connection from  ('127.0.0.1', 53654)
Send packet returned: 1
execute: 1 -> 2
0,36; 2
Send packet returned: 2
execute: 2 -> 4
0,66; 4
Send packet returned: 4
execute: 4 -> 8
0,95; 8
Send packet returned: 8
execute: 8 -> 16
1,28; 16
Send packet returned: 16
execute: 16 -> 32
1,85; 32
Send packet returned: 32
execute: 32 -> 64
3,02; 64
Send packet returned: 64
execute: 64 -> 128
5,35; 128
Send packet returned: 128
execute: 128 -> 256
8,97; 256
Send packet returned: 256
execute: 256 -> 512
18,17; 512
send packets: 512 -> 256.0
28,84; 256
Send packet returned: 256.0
execute: 256.0 -> 512.0
38,54; 512
send packets: 512.0 -> 256.0
48,62; 256
Send packet returned: 256.0
execute: 256.0 -> 512.0
54,73; 512
Send packet returned: 512.0
execute: 512.0 -> 1024.0
61,23; 1024
send packets: 1024.0 -> 512.0
71,58; 512
Send packet returned: 512.0
execute: 512.0 -> 1024.0
81,75; 1024
send packets: 1024.0 -> 512.0
91,94; 512
send packets: 512.0 -> 256.0
102,01; 256
Send packet returned: 512.0
execute: 512.0 -> 1024.0
108,74; 1024

虽然send_packets(递归调用两次)将sizeWindow 除以四(从1024 到512 到256),但execute 方法获取的返回值是512 而不是256。

【讨论】:

  • 效果非常好,非常感谢 AlexisBRENON !!!只是一个问题,因为我是一个新的 Python 学习者,我想问你是否应该像你一样创建这些类,这样创建它们是否更 Pythonic?再次非常感谢!
  • @Codewraith 不一定。关于何时/何地在 Python 中使用类存在很多争论(link1link2)。凭借 C++/Java/Kotlin 编程的深厚背景,即使在不需要时,我也经常使用类。在这种特殊情况下,也许用target 实例化Thread 会更合适。一切都取决于您的代码组织。
  • 好的,我会看一下这个链接,再次感谢您的解释。
  • 我遇到了另一个 TCP 连接问题,当我尝试使用两台计算机时,当客户端丢失数据包时,我无法将客户端重新连接到服务器,是否有另一种方法可以重新连接它们而无需失去连接?我为这个问题创建了另一个问题,但我还没有找到解决这个问题的方法。
猜你喜欢
  • 1970-01-01
  • 2014-03-03
  • 2018-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
  • 1970-01-01
相关资源
最近更新 更多