【问题标题】:Python Socket Receive for multiple TCP headers用于多个 TCP 标头的 Python 套接字接收
【发布时间】:2015-12-12 06:52:33
【问题描述】:

我是 Python 的初学者,所以请考虑一下我无法一次性提供完整的信息。

我的要求是:

我正在实现一个基于 Python 的套接字接收器。实施已完成,但我必须处理以下消息/数据流:

1) 数据流将包含 4 种不同类型的消息。每个都有一个我正在使用的消息头(1-4)

type_msg=struct.unpack('B',data[0])[0]

2) 第二部分是接下来的 4 位将根据标头具有每种类型数据的实际长度。所以,

actual_len = struct.unpack('i', data[1:5])[0]

3) 下一部分是处理接收到的数据并使用它。接收到的数据长度可以取**rcv_len = len(data)**

在收到的数据少于/多于实际长度的情况下,我遇到了问题。我有使用actual_len-rcv_len 得到的delta-length

在此之后我无法处理代码。到目前为止,接收增量消息然后将其附加到接收到的数据的最佳方法是什么。我也想将数据写入文件。

我已阅读有关 data.append 的信息,但不太确定如何实现它。我应该再次使用 conn.recv(del_len) 接收数据还是做其他事情。

任何指导都会非常有帮助。

在下面添加代码:

BUFFER_SIZE=40960
import socket
import struct

class mySocket:

def __init__(self, sock=None):
    if sock is None:
        self.sock = socket.socket(
                        socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(('', 9988)) 
        self.sock.listen(1)
    else:
        self.sock = sock

def receive_data(self):
    # Wait for a connection
    print >>sys.stderr, 'waiting for a connection'
    conn, client_address= self.sock.accept()
    print "Connected to client with IP---->", client_address
    while True:
        data = conn.recv(BUFFER_SIZE) 
        if not data:
            print "Connection is Broken.."
            break
        else: 
            if data<5:
                print "MSG HEADER STILL NOT COMPLETELY RECEIVED"
            else:
                type_msg=struct.unpack('B',data[0])
                msg_type = type_msg[0]
                rcv_len = len(data)
                actual_len = struct.unpack('i', data[1:5])[0]
                print "Received Length: ",rcv_len
                print "Actual Length : ",actual_len
                if msg_type == 1:
                    f_cfg = open("test.xml", "wb")
                    if rcv_len < actual_len:
                        del_len = actual_len-rcv_len
                        print "Delta length :",del_len
                        while (del_len):
                            print "Receiving Falcon Config File..."
                            print "Actual Length : ",actual_len,"and total length now is",rcv_len+del_len
                            f_cfg.write(data[5:rcv_len]+data[del_len]) //Feel something wrong in this.
                    else:
                        print "Writing Falcon config"
                        f_cfg.write(data[5:])
                    f_cfg.close()
                else:
                    print "INVALID MESSAGE TYPE. DATA CORRUPTED !!"
                    break

    conn.send("Data Received")
    conn.close()

【问题讨论】:

    标签: python sockets tcp


    【解决方案1】:

    你很接近。诀窍是永远不要在任何步骤中读取比您需要的更多的数据,这样您就不必担心过度拍摄。并且只需通过减去每次收到的金额来跟踪剩余的数据,这样您就不必处理多个变量。

    这是一个读取固定大小缓冲区的助手。用它来读取标题。

    def recv_exactly(sock, count):
        """receive exactly count bytes from socket. If socket is closed,
        empty string is returned even if some data received.
        """
        buf = []
        while count:
            data = sock.recv(count)
            if not data:
                return ''
            count -= len(data)
            buf.append(data)
        return ''.join(buf)
    

    您可以使用相同的函数来读入数据,但最好是边写边写文件。注意在接收数据时,min函数用于决定recv大小。

    def receive_data(self):
        # Wait for a connection
        print >>sys.stderr, 'waiting for a connection'
        conn, client_address= self.sock.accept()
        print "Connected to client with IP---->", client_address
        while True:
            # read fix length header
            data = recv_exactly(conn, 5) 
            if not data:
                print "Connection is Broken.."
                break
            msg_type, data_len = struct.unpack('Bi', data)
    
            if msg_type == 1:
                # read stream into file
                with open('test.xml', 'wb') as fp:
                    while data_len:
                        # read next chunk. on the last chunk, limit recv to the
                        # known amount of outstanding data
                        data = conn.recv(min(data_len, BUFFER_SIZE))
                        if not data:
                            print "ERROR: TOO FEW BYTES RECEIVED"
                            break
                        fp.write(data)
                        data_len -= len(data)
    
        conn.send("Data Received")
        conn.close()
    

    【讨论】:

    • 感谢您的详尽回答...我会尽力回复。
    • 当我必须检查 2 个不同的 msg_type 时,您能否告诉我如何处理接收部分。还有 msg_type, data_len = struct.unpack('Bi', data),我得到 "struct.error: unpack requires a string argument of length 8" 错误。
    • 我忽略了填充 - 默认情况下,结构将在 B 之后添加 3 个字节以在 32 位边界上对齐。您可以使用修饰符之一更改此设置=(本机字节顺序)、&lt;(小端)、&gt;(大端)、!(网络顺序)。由于您的格式字符串"i" 是本机顺序,您可以使用"=Bi"。由于这是一个网络协议,因此使用! 是有意义的,但前提是发送端生成流量的代码执行相同的操作。
    • 添加"=Bi" 成功了!棺材上只剩下最后一颗钉子了。假设发送方发送了多个具有不同 msg_type 的文件。所以对于文件 A,我有 msg_type=1,对于文件 B,我有 msg_type=2。现在我想检查哪个 msg_type 来了并用它做我的事情,然后使用 TCP 发送的其余部分数据来检测其他 msg_type 和数据。由于我无法控制一次突发将发送多少数据,因此代码也应该能够处理该部分。
    • 你已经成功了。当当前代码完成文件副本时,它会转到while 的顶部并等待下一个标头。您可以为剩余的消息类型添加elif 子句。我的代码假设所有标题都是 5 个字节(msg 类型和数据计数)。如果根据类型有不同大小的标头,则应先读取 1 字节的 msg 类型。
    猜你喜欢
    • 2018-07-09
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 2021-01-14
    • 2018-10-12
    • 1970-01-01
    相关资源
    最近更新 更多