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读取了

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