Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:通过套接字发送的消息的大小_Python_Sockets - Fatal编程技术网

Python:通过套接字发送的消息的大小

Python:通过套接字发送的消息的大小,python,sockets,Python,Sockets,我正在尝试使用socket库发送消息。由于消息的大小是可变的,所以我决定在字符串的开头追加消息的大小,然后发送消息。例如,如果消息是 Hello World! 这是13个字符长(我已经计算了EOL),我会发送类似 sizeof13charsinbytes|Hello World! 通过socket.send(),然后使用str.split() 由于socket.recv()需要以字节为单位的消息大小,如何查找消息的大小?我尝试了sys.getsizeof(),但它为单个字符串提供了任意值。它

我正在尝试使用
socket
库发送消息。由于消息的大小是可变的,所以我决定在字符串的开头追加消息的大小,然后发送消息。例如,如果消息是

Hello World!
这是13个字符长(我已经计算了EOL),我会发送类似

sizeof13charsinbytes|Hello World!
通过
socket.send()
,然后使用
str.split()


由于
socket.recv()
需要以字节为单位的消息大小,如何查找消息的大小?我尝试了
sys.getsizeof()
,但它为单个字符串提供了任意值。它的大小是否正确?

在这种情况下,读取标题以获取大小,然后读取有效负载是很常见的。如果标题是固定大小的(可能是一个二进制整数,可能是一个带填充的固定大小的ascii字符串),则更容易一些,但也可以逐个字符读取,直到找到诸如“|”之类的分隔符。我在下面有几个样品

import struct

def _get_block(s, count):
    if count <= 0:
        return ''
    buf = ''
    while len(buf) < count:
        buf2 = s.recv(count - len(buf))
        if not buf2:
            # error or just end of connection?
            if buf:
                raise RuntimeError("underflow")
            else:
                return ''
        buf += buf2
    return buf

def _send_block(s, data):
    while data:
        data = data[s.send(data):]

if False:
    def get_msg(s):
        count = struct.unpack('>i', _get_block(s, 4))[0]
        return _get_block(s, count)

    def send_msg(s, data):
        header = struct.pack('>i', len(data))
        _send_block(s, header)
        _send_block(s, data)

if True:

    def _get_count(s):
        buf = ''
        while True:
            c = s.recv(1)
            if not c:
                # error or just end of connection/
                if buf:
                    raise RuntimeError("underflow")
                else:
                    return -1
            if c == '|':
                return int(buf)
            else:
                buf += c

    def get_msg(s):
        return _get_block(s, _get_count(s))

    def send_msg(s, data):
        _send_block(s, str(len(data)) + '|')
        _send_block(s, data)


import threading
import socket
import time

def client(port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('0.0.0.0', port))
    print get_msg(s)
    print get_msg(s)
    s.shutdown(socket.SHUT_RDWR)
    s.close()

def server(port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', port))
    s.listen(1)
    c, addr = s.accept()
    send_msg(c, 'hello')
    send_msg(c, 'there')
    c.close()
    s.close()

if __name__ == '__main__':
    c = threading.Thread(target=server, args=(8999,))
    c.start()
    time.sleep(1)
    client(8999)
    c.join()
    print 'done'
导入结构
def_获取_块,计数:

如果计数则没有必要重新发明轮子。通过使用
multiprocessing.connection
模块将字符串作为python字符串对象发送,可以轻松地发送可变长度字符串。此方法将允许发送大多数python对象,而不仅仅是字符串

import multiprocessing
import multiprocessing.connection as connection

def producer(data, address, authkey):
    with connection.Listener(address, authkey=authkey) as listener:
        with listener.accept() as conn:
            print('connection accepted from', listener.last_accepted)
            for item in data:
                print("producer sending:", repr(item))
                conn.send(item)


def consumer(address, authkey):
    with connection.Client(address, authkey=authkey) as conn:
        try:
            while True:
                item = conn.recv()
                print("consumer received:", repr(item))
        except EOFError:
            pass

listen_address = "localhost", 50000
remote_address = "localhost", 50000
authkey = b'secret password'

if __name__ == "__main__":
    data = ["1", "23", "456"]
    p = multiprocessing.Process(target=producer, args=(data, listen_address, authkey))
    p.start()
    consumer(remote_address, authkey)
    p.join()
    print("done")
这会产生如下结果:

producer sending: '1'
producer sending: '23'
consumer received: '1'
producer sending: '456'
consumer received: '23'
consumer received: '456'
done

序列化数据后,您可以简单地使用
len(您的序列化数据)
获取其长度

下面是发送和接收函数的示例,您可以在客户端和服务器端使用该函数发送和接收可变长度的数据

def send_data(conn, data):
    serialized_data = pickle.dumps(data)
    conn.sendall(struct.pack('>I', len(serialized_data)))
    conn.sendall(serialized_data)


def receive_data(conn):
    data_size = struct.unpack('>I', conn.recv(4))[0]
    received_payload = b""
    reamining_payload_size = data_size
    while reamining_payload_size != 0:
        received_payload += conn.recv(reamining_payload_size)
        reamining_payload_size = data_size - len(received_payload)
    data = pickle.loads(received_payload)

    return data

我猜您可以在

找到示例程序,如果False表示大小为固定大小的消息,如果True表示大小为非固定大小的消息,那么给出字符串长度而不是字节大小是否正确?我想您可以将它乘以字符的大小,但当您尝试读取消息时,您指定的是字符串长度,而不是它的大小(如果为True)。该示例是在python 2上编写的,其中数据以1字节字符的形式输入,因此长度和字符数是相同的。如果你想要一种不同的编码,或者想在Python3上使用它,那么你就必须添加它。答案不错,但将发送方和接收方限制为python代码。你说得很对,这是不利的一面。老实说,我没有考虑过这种可能性。