python 序列化 通过网络发送_Python中自定义的实例通过网络进行传送

本文演示了如何使用Python的pickle模块将自定义对象序列化并通过UDP协议在网络间传输。通过服务端和客户端的代码示例,展示了如何处理接收方无法识别发送方自定义类的问题,利用exec函数在全局作用域中创建类对象,从而实现对象的反序列化和恢复。
摘要由CSDN通过智能技术生成

Python中万物皆对象,假如我们需要在网络中传输数据,必须转换成二进制的格式。

所以我们需要将具体的对象转换成字节码,然后通过socket进行网络输送。

对于Python内置的字符串对象可以encode编码成字节码,全部的对象(包含字符串)可以通过pickle模块转换成字节码,对方收到消息直接反序列化就可以拿到对象。

下面我通过简单的UDP协议进行数据传输试验:

服务端文件:

#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

import socket

import pickle

MAX_BYTES = 65535

def server(port):

# 建立端口,设定ip传输协议以及端口协议

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定指定的ip与端口

sock.bind(('127.0.0.1', port))

print('Listening at {}'.format(sock.getsockname()))

while True:

# 接收信息

data, address = sock.recvfrom(MAX_BYTES)

# 解码

text = pickle.loads(data)

print('The client at {} says {!r}'.format(address, text))

text = 'Your data was {} bytes long'.format(len(data))

data = text.encode('ascii')

# 发送信息

sock.sendto(data, address)

if __name__ == '__main__':

server(1060)

客户端文件

#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

import socket

import pickle

from datetime import datetime

MAX_BYTES = 65535

def client(port, data):

# 建议端口

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

text = 'The time is {}'.format(datetime.now())

print(text)

data = pickle.dumps(data)

# 发送消息

sock.sendto(data, ('127.0.0.1', port))

print('The OS assigned me the address {}'.format(sock.getsockname()))

data, address = sock.recvfrom(MAX_BYTES) # Danger! See Chapter 2

text = data.decode('ascii')

print('The server {} replied {!r}'.format(address, text))

if __name__ == '__main__':

for i in [range(5), list('abc'), dict(a=1,b=2)]:

client(1060, i)

执行 客户端

(base) shijianzhongdeMacBook-Pro:chapter02 shijianzhong$ python client_host.py

The time is 2020-12-09 13:01:55.207264

The OS assigned me the address ('0.0.0.0', 53972)

The server ('127.0.0.1', 1060) replied 'Your data was 43 bytes long'

The time is 2020-12-09 13:01:55.207624

The OS assigned me the address ('0.0.0.0', 59785)

The server ('127.0.0.1', 1060) replied 'Your data was 28 bytes long'

The time is 2020-12-09 13:01:55.207813

The OS assigned me the address ('0.0.0.0', 50027)

The server ('127.0.0.1', 1060) replied 'Your data was 28 bytes long'

服务端输出

(base) shijianzhongdeMacBook-Pro:chapter02 shijianzhong$ python server_host.py

Listening at ('127.0.0.1', 1060)

The client at ('127.0.0.1', 53972) says range(0, 5)

The client at ('127.0.0.1', 59785) says ['a', 'b', 'c']

The client at ('127.0.0.1', 50027) says {'a': 1, 'b': 2}

可以实现通讯。

当客户端传送给具体的Python对象给服务端时,服务端无法加载该对象。会报错

File "server_host.py", line 28, in

server(1060)

File "server_host.py", line 19, in server

text = pickle.loads(data)

AttributeError: Can't get attribute 'A' on

这个时候,需要对服务端进行进行一些调整,需要把原来的类传过来,并输入到该模块中

服务端代码:

#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

import socket

import pickle

MAX_BYTES = 65535

def server(port):

# 建立端口,设定ip传输协议以及端口协议

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定指定的ip与端口

sock.bind(('127.0.0.1', port))

print('Listening at {}'.format(sock.getsockname()))

while True:

# 接收信息

data, address = sock.recvfrom(MAX_BYTES)

# 解码

text = pickle.loads(data)

if type(text) == str:

#由于这是在函数里面运行,执行exec无法给模块赋值,所以绕了一圈

# 再次强调下,由于在函数内部执行exec无法给模块赋值这个类的属性,需要先输出到自定义的作用域,再传给全局

# 在函数中执行,只会在函数的作用域中产生这个类对象,但后续的实例化的时候,需要全局查找该类对象。

g = {}

# 执行赋值给g为

exec(text, g)

# 全局编码赋值此类

globals()['A'] = g['A']

else:

print(text.name)

print('The client at {} says {!r}'.format(address, text))

text = 'Your data was {} bytes long'.format(len(data))

data = text.encode('ascii')

# 发送信息

sock.sendto(data, address)

if __name__ == '__main__':

server(1060)

客户端代码

#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

import socket

import pickle

from datetime import datetime

import inspect

MAX_BYTES = 65535

class A:

pass

def client(port, data):

# 建议端口

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

text = 'The time is {}'.format(datetime.now())

print(text)

data = pickle.dumps(data)

# 发送消息

sock.sendto(data, ('127.0.0.1', port))

print('The OS assigned me the address {}'.format(sock.getsockname()))

data, address = sock.recvfrom(MAX_BYTES) # Danger! See Chapter 2

text = data.decode('ascii')

print('The server {} replied {!r}'.format(address, text))

if __name__ == '__main__':

content = inspect.getsource(A)

a = A()

a.name = 'sidian'

client(1060, content)

client(1060, a)

执行后输出

(base) shijianzhongdeMacBook-Pro:chapter02 shijianzhong$ python server_host.py

Listening at ('127.0.0.1', 1060)

The client at ('127.0.0.1', 64398) says 'class A:\npass\n'

sidian

The client at ('127.0.0.1', 65487) says

这里需要注意一下,类的定义要在__main__前面定义!

通过此方法就可以将一个对象传递给另外一个Python脚本进程,实现自定义对象的传递。

这里面主要用到了exec执行字符串命令的方式,给全局变量赋值该类为属性,那后续实例就可以直接通过pickle.loads读取了

感觉还时很骚包的,一般应该用不到,哈哈哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值