Python中自定义的实例通过网络进行传送

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无法给模块赋值,所以绕了一圈
        # 再次强调下,由于在函数内部执行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:\n    pass\n'

sidian

The client at ('127.0.0.1', 65487) says <A object at 0x7fb8158a1280>

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

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

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

 

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

posted @ 2020-12-09 14:13  就是想学习  阅读(477)  评论(0编辑  收藏  举报