在 Python 中通过套接字发送和接收对象

新手上路,请多包涵

我在 Internet 上搜索了很多,但一直无法找到通过套接字发送对象并按原样接收对象的解决方案。我知道它需要我已经做过的酸洗。然后将其转换为字节并在另一方面接收。但是我怎样才能将这些字节转换成那种类型的对象呢?

 process_time_data = (current_process_start_time, current_process_end_time)
prepared_process_data = self.prepare_data_to_send(process_time_data)
data_string = io.StringIO(prepared_process_data)
data_string =  pack('>I', len(data_string)) + data_string
self.send_to_server(data_string)

这是在客户端将对象转换为 StringIO 并发送到服务器的代码。在服务器端,我正在获取字节。现在我正在搜索要再次转换为 StringIO 的字节,以便我可以获得对象值。

在代码中,Object 被包装在 StringIO 中并通过套接字发送。有更好的方法吗?

服务器端代码如下。

 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#server.setblocking(0)
server.bind(('127.0.0.1', 50000))
server.listen(5)
inputs = [server]
outputs = []
message_queues = {}

while inputs:
    readable, writeable, exceptional = select.select(inputs, outputs, inputs)
    for s in readable:
        if s is server:
            connection, client_address = s.accept()
            print(client_address)
            connection.setblocking(0)
            inputs.append(connection)
            message_queues[connection] = queue.Queue()
            print('server started...')
        else:
            print('Getting data step 1')
            raw_msglen = s.recv(4)
            msglen = unpack('>I', raw_msglen)[0]
            final_data = b''
            while len(final_data) < msglen:
                data = s.recv(msglen - len(final_data))
                if data:
                    #print(data)
                    final_data += data
                    message_queues[s].put(data)
                    if s not in outputs:
                        outputs.append(s)
                    else:
                        if s in outputs:
                            outputs.remove(s)
                else:
                    break
            inputs.remove(connection)
            #s.close()
            del message_queues[s]

            process_data = ProcessData()
            process_screen = ProcessScreen()

            if final_data is not None:
                try:
                    deserialized_data = final_data.decode("utf-8")
                    print(deserialized_data)
                except (EOFError):
                    break
            else:
                print('final data is empty.')

            print(process_data.project_id)
            print(process_data.start_time)
            print(process_data.end_time)
            print(process_data.process_id)

两个辅助函数如下:

 def receive_all(server, message_length, message_queues, inputs, outputs):
    # Helper function to recv message_length bytes or return None if EOF is hit
    data = b''
    while len(data) < message_length:
        packet = server.recv(message_length - len(data))
        if not packet:
            return None
        data += packet
        message_queues[server].put(data)
        if server not in outputs:
            outputs.append(server)
        else:
            if server in outputs:
                outputs.remove(server)
    inputs.remove(server)
    del message_queues[server]
    return data

def receive_message(server, message_queues, inputs, outputs):
    # Read message length and unpack it into an integer
    raw_msglen = receive_all(server, 4, message_queues, inputs, outputs)
    if not raw_msglen:
        return None
    message_length = unpack('>I', raw_msglen)[0]

    return receive_all(server, message_length, message_queues, inputs, outputs)

其中两个模型类如下:

 class ProcessData:
    process_id = 0
    project_id = 0
    task_id = 0
    start_time = 0
    end_time = 0
    user_id = 0
    weekend_id = 0

# Model class to send image data to the server
class ProcessScreen:
    process_id = 0
    image_data = bytearray()

原文由 Dharmindar 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 379
2 个回答

您正在寻找 泡菜loadsdumps 操作。套接字基本上是字节流。让我们考虑一下您遇到的情况。

 class ProcessData:
    process_id = 0
    project_id = 0
    task_id = 0
    start_time = 0
    end_time = 0
    user_id = 0
    weekend_id = 0

此类的实例需要通过执行 data_string = pickle.dumps(ProcessData()) 被腌制到数据字符串中,并通过执行 data_variable = pickle.loads(data) 取消腌制,其中 data 收到的是什么。

因此,让我们考虑这样一种情况:客户端创建一个对象 ProcessData 并将其发送到服务器。这是客户端的样子。这是一个最小的例子。

客户

import socket, pickle

class ProcessData:
    process_id = 0
    project_id = 0
    task_id = 0
    start_time = 0
    end_time = 0
    user_id = 0
    weekend_id = 0

HOST = 'localhost'
PORT = 50007
# Create a socket connection.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

# Create an instance of ProcessData() to send to server.
variable = ProcessData()
# Pickle the object and send it to the server
data_string = pickle.dumps(variable)
s.send(data_string)

s.close()
print 'Data Sent to Server'

现在您接收此数据的服务器如下所示。

服务器

import socket, pickle

class ProcessData:
    process_id = 0
    project_id = 0
    task_id = 0
    start_time = 0
    end_time = 0
    user_id = 0
    weekend_id = 0

HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr

data = conn.recv(4096)
data_variable = pickle.loads(data)
conn.close()
print data_variable
# Access the information by doing data_variable.process_id or data_variable.task_id etc..,
print 'Data received from client'

运行服务器首先在端口上创建一个 _绑定_,然后运行 客户端 通过套接字进行数据传输。你也可以看看 这个答案

原文由 Sudheesh Singanamalla 发布,翻译遵循 CC BY-SA 4.0 许可协议

无耻地插在这里,但我和一个朋友最近发布了 tlspyo ,这是一个开源库,其目的是帮助您以安全的方式轻松地通过网络传输 python 对象。

通过 Internet 套接字传输 pickled 对象而不使用 tlspyo 之类的东西基本上是为黑客敞开的大门,所以不要这样做。

使用 tlspyo,您的代码如下所示:

服务器:

 from tlspyo import Relay

if __name__ == "__main__":
    my_server = Relay(port=3000,password="<same strong password>")

    # (...)

客户 1:

 from tlspyo import Endpoint

if __name__ == "__main__":
    client_1 = Endpoint(
        ip_server='<ip of your server>'
        port=3000,
        password="<same strong password>",
        groups="client 1")

    # send an object to client 2:
    my_object = "my object"  # doesn't have to be a string, of course
    client_1.broadcast(my_object, "client 2")

    # (...)

客户 2:

 from tlspyo import Endpoint

if __name__ == "__main__":
    client_2 = Endpoint(
        ip_server='<ip of my Relay>'
        port=3000,
        password="<same strong password>",
        groups="client 2")

    # receive the object sent by client 1:
    my_object = client_2.receive_all(blocking=True)[0]

    # (...)

(您需要设置 TLS 才能使此代码正常工作,查看 文档- 或者您可以使用 security=None 禁用 TLS,但如果您通过 Internet 传输,您不想这样做。)

原文由 Yann Bouteiller 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题