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 <module>
server(1060)
File "server_host.py", line 19, in server
text = pickle.loads(data)
AttributeError: Can't get attribute 'A' on <module '__main__' from 'server_host.py'>
这个时候,需要对服务端进行进行一些调整,需要把原来的类传过来,并输入到该模块中
服务端代码:
#!/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无法给模块赋值,所以绕了一圈 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: pass '
sidian
The client at ('127.0.0.1', 65487) says <A object at 0x7fb8158a1280>
这里需要注意一下,类的定义要在__main__前面定义!
通过此方法就可以将一个对象传递给另外一个Python脚本进程,实现自定义对象的传递。
这里面主要用到了exec执行字符串命令的方式,给全局变量赋值该类为属性,那后续实例就可以直接通过pickle.loads读取了
感觉还时很骚包的,一般应该用不到,哈哈哈哈