在套接字 Python 中发送 pickled class 对象
Sending pickled class object in socket Python
我正在尝试从客户端向服务器端发送一个 class 对象。我尝试腌制 class 并通过套接字发送腌制字节,但该值未传递到服务器端。
客户端utils.py
from collections import defaultdict
class Utils:
_filter_ip = []
_filter_vrf = defaultdict(list)
@classmethod
def filter_ip(cls):
return cls._filter_ip
@classmethod
def set_filter_ip(cls, ip_list):
cls._filter_ip = ip_list
@classmethod
def filter_vrf(cls):
return cls._filter_vrf
@classmethod
def set_filter_vrf(cls, device_name, vrf_list):
cls._filter_vrf[device_name] = vrf_list
客户端client.py
import socket
import pickle
from utils import Utils
HOST = '127.0.0.1'
PORT = 5001
s = socket.socket()
s.connect((HOST, PORT))
Utils.set_filter_ip(['0.0.0.0/0', '10.0.0.0/8'])
Utils.set_filter_vrf('device1', ['vrf1', 'vrf2'])
pickled_data = pickle.dumps(Utils)
s.send(pickled_data)
服务器端utils.py
from collections import defaultdict
class Utils:
_filter_ip = []
_filter_vrf = defaultdict(list)
@classmethod
def filter_ip(cls):
return cls._filter_ip
@classmethod
def set_filter_ip(cls, ip_list):
cls._filter_ip = ip_list
@classmethod
def filter_vrf(cls):
return cls._filter_vrf
@classmethod
def set_filter_vrf(cls, device_name, vrf_list):
cls._filter_vrf[device_name] = vrf_list
服务器端server.py
import socket
import os
import json
import pickle
from utils import Utils
class Server:
_SERVER_HOST = '127.0.0.1'
_SERVER_PORT = 5001
_BUFFER_SIZE = 4096
_SEPARATOR = '<SEPERATOR>'
def __init__(self):
self._socket = socket.socket()
self._client = None
def init_socket(self):
self._socket.bind((self._SERVER_HOST, self._SERVER_PORT))
self._socket.listen(5)
def listen_socket(self):
self._client, address = self._socket.accept()
def recv_data(self):
data = self._client.recv(self._BUFFER_SIZE)
pickled_data = pickle.loads(data)
print(pickled_data.filter_ip())
def run_server(self):
self.init_socket()
self.listen_socket()
while True:
self.recv_data()
recv_data 方法打印来自 Utils class 的 unpickled 对象,但 Utils class 中的数据丢失(filter_ip 和 filter_vrf) .需要一些帮助来指出我犯的错误。
阅读文档是个好主意。 this section中解释为:
Note that functions (built-in and user-defined) are pickled by “fully
qualified” name reference, not by value. [2] This means that only the
function name is pickled, along with the name of the module the
function is defined in. Neither the function’s code, nor any of its
function attributes are pickled. Thus the defining module must be
importable in the unpickling environment, and the module must contain
the named object, otherwise an exception will be raised. [3]
Similarly, classes are pickled by named reference, so the same
restrictions in the unpickling environment apply.
但是,在 this section 中以及如何允许对 给定 class 进行自定义酸洗的示例可以实现:
import io
import pickle
class MyClass:
my_attribute = 1
class MyPickler(pickle.Pickler):
def reducer_override(self, obj):
"""Custom reducer for MyClass."""
if getattr(obj, "__name__", None) == "MyClass":
return type, (obj.__name__, obj.__bases__,
{'my_attribute': obj.my_attribute})
else:
# For any other object, fallback to usual reduction
return NotImplemented
f = io.BytesIO()
p = MyPickler(f)
p.dump(MyClass)
del MyClass
unpickled_class = pickle.loads(f.getvalue())
assert isinstance(unpickled_class, type)
assert unpickled_class.__name__ == "MyClass"
assert unpickled_class.my_attribute == 1
所以在你的情况下,如果真的这么简单,就像:
class MyPickler(pickle.Pickler):
def reducer_override(self, obj):
"""Custom reducer for Utils."""
if getattr(obj, "__name__", None) == "Utils":
return type, (obj.__name__, obj.__bases__, vars(obj))
else:
# For any other object, fallback to usual reduction
return NotImplemented
可以工作。
我正在尝试从客户端向服务器端发送一个 class 对象。我尝试腌制 class 并通过套接字发送腌制字节,但该值未传递到服务器端。
客户端utils.py
from collections import defaultdict
class Utils:
_filter_ip = []
_filter_vrf = defaultdict(list)
@classmethod
def filter_ip(cls):
return cls._filter_ip
@classmethod
def set_filter_ip(cls, ip_list):
cls._filter_ip = ip_list
@classmethod
def filter_vrf(cls):
return cls._filter_vrf
@classmethod
def set_filter_vrf(cls, device_name, vrf_list):
cls._filter_vrf[device_name] = vrf_list
客户端client.py
import socket
import pickle
from utils import Utils
HOST = '127.0.0.1'
PORT = 5001
s = socket.socket()
s.connect((HOST, PORT))
Utils.set_filter_ip(['0.0.0.0/0', '10.0.0.0/8'])
Utils.set_filter_vrf('device1', ['vrf1', 'vrf2'])
pickled_data = pickle.dumps(Utils)
s.send(pickled_data)
服务器端utils.py
from collections import defaultdict
class Utils:
_filter_ip = []
_filter_vrf = defaultdict(list)
@classmethod
def filter_ip(cls):
return cls._filter_ip
@classmethod
def set_filter_ip(cls, ip_list):
cls._filter_ip = ip_list
@classmethod
def filter_vrf(cls):
return cls._filter_vrf
@classmethod
def set_filter_vrf(cls, device_name, vrf_list):
cls._filter_vrf[device_name] = vrf_list
服务器端server.py
import socket
import os
import json
import pickle
from utils import Utils
class Server:
_SERVER_HOST = '127.0.0.1'
_SERVER_PORT = 5001
_BUFFER_SIZE = 4096
_SEPARATOR = '<SEPERATOR>'
def __init__(self):
self._socket = socket.socket()
self._client = None
def init_socket(self):
self._socket.bind((self._SERVER_HOST, self._SERVER_PORT))
self._socket.listen(5)
def listen_socket(self):
self._client, address = self._socket.accept()
def recv_data(self):
data = self._client.recv(self._BUFFER_SIZE)
pickled_data = pickle.loads(data)
print(pickled_data.filter_ip())
def run_server(self):
self.init_socket()
self.listen_socket()
while True:
self.recv_data()
recv_data 方法打印来自 Utils class 的 unpickled 对象,但 Utils class 中的数据丢失(filter_ip 和 filter_vrf) .需要一些帮助来指出我犯的错误。
阅读文档是个好主意。 this section中解释为:
Note that functions (built-in and user-defined) are pickled by “fully qualified” name reference, not by value. [2] This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised. [3]
Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply.
但是,在 this section 中以及如何允许对 给定 class 进行自定义酸洗的示例可以实现:
import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1
所以在你的情况下,如果真的这么简单,就像:
class MyPickler(pickle.Pickler):
def reducer_override(self, obj):
"""Custom reducer for Utils."""
if getattr(obj, "__name__", None) == "Utils":
return type, (obj.__name__, obj.__bases__, vars(obj))
else:
# For any other object, fallback to usual reduction
return NotImplemented
可以工作。