rpc 的使用
rpc就是将本地的方法放到了服务器端,使得网络通信如同调用方法般简单。
import RemoteCallMethod_pb2
import functools
import ProtobufHelper
from socket import AF_INET,SOCK_STREAM,socket
class RemoteCallClient:
buffsize=1024
def __init__(self,host,port):
self.host = host
self.port = port
ADDR=(HOST , PORT)
self.client = socket(AF_INET,SOCK_STREAM)
self.client.connect(ADDR)
def __getattr__(self,method_name):
return functools.partial(self.execute,method_name)
def execute(self,method_name,*args,**kwargs):
helper = ProtobufHelper.ProtobufHelper()
remoteMethodCall = RemoteCallMethod_pb2.RemoteCallMethod()
remoteMethodCall.methodName = method_name
remoteMethodCall.methodArgs = helper.parseToProtobuf(args)
remoteMethodCall.methodKwargs = helper.parseToProtobuf(kwargs)
strData = remoteMethodCall.SerializeToString()
self.client.send(strData)
data = self.client.recv(self.buffsize)
remoteCallRespon = RemoteCallMethod_pb2.RemoteCallRespon()
remoteCallRespon.ParseFromString(data)
return remoteCallRespon.methodRespon
HOST='127.0.0.1'
PORT=5000
remoteCallClient = RemoteCallClient(HOST,PORT)
print remoteCallClient.add(3,4)
#print remoteCallClient.sub(3,4)
服务端代码
'''
Created on 2015-1-12
@author: Administrator
'''
from gevent.server import StreamServer
from tool import RemoteCallMethod_pb2
from tool import ProtobufHelper
class RemoteCallSever:
buffsize=1024
def __init__(self,host,port):
self.server = StreamServer((host,port),self.handle)
self.server.serve_forever()
def handle(self,socket,address):
data = socket.recv(self.buffsize)
remoteMethodCall = RemoteCallMethod_pb2.RemoteCallMethod()
remoteMethodCall.ParseFromString(data)
helper = ProtobufHelper.ProtobufHelper()
methodName = remoteMethodCall.methodName
args = helper.parseFromProtobuf(remoteMethodCall.methodArgs)
kwargs = helper.parseFromProtobuf(remoteMethodCall.methodKwargs)
method = getattr(self,methodName,None)
remoteCallRespon = RemoteCallMethod_pb2.RemoteCallRespon()
if not callable(method):
remoteCallRespon.methodRespon = 'no this method'
else :
remoteCallRespon.methodRespon = str(method(*args,**kwargs))
strData = remoteCallRespon.SerializeToString()
socket.send(strData)
def add(self,a,b):
return a+b
HOST='127.0.0.1'
PORT=5000
print "\r"
remoteCallServer = RemoteCallSever(HOST,PORT)
protobuf帮助类
'''
Created on 2015-1-13
@author: Administrator
'''
class ProtobufHelper:
def __init__(self):
pass
def parseFromDict(self,values,type):
typestr = type + ':'
dictStr = ''
for value in values:
if len(dictStr) % 2 == 1:
dictStr += ':'
elif len(dictStr) > 0 and len(dictStr) % 2 == 0:
dictStr += ';'
dictStr += str(value)
return typestr+dictStr
def parseFromTuple(self,values,type):
typestr = type + ':'
tupleStr = ''
for value in values:
if len(tupleStr) > 0:
tupleStr += ','
tupleStr += str(value)
return typestr+tupleStr
def parseToProtobuf(self,values):
if isinstance(values,dict):
return self.parseFromDict(values,'dict')
elif isinstance(values,tuple):
return self.parseFromTuple(values,'tuple')
elif isinstance(values,list):
return self.parseFromTuple(values,'list')
def parseToDict(self,values):
value = '{' + values + '}'
return eval(value)
def parseToTuple(self,values):
value = '(' + values + ')'
return eval(value)
def parseToList(self,values):
value = '[' + values + ']'
return eval(value)
def parseFromProtobuf(self,values):
npos = values.find(':')
type = values[:npos]
substr = values[npos+1:]
if type == 'tuple' :
return self.parseToTuple(substr)
elif type == 'dict' :
return self.parseToDict(substr)
elif type == 'list' :
return self.parseToList(substr)
协议
package rpcMessage;
message RemoteCallMethod {
required string methodName = 1;
required string methodArgs = 2;
required string methodKwargs = 3;
}
message RemoteCallRespon
{
required string methodRespon = 1;
}
要注意的几点:
1、当类中无此方法时会进入到__getattr__
2、此时构建数据包进行通信,等待应答
3、远程收到消息后通过method = getattr(self,methodName,None),判断类中有无方法
4、进行应答响应
5、原等待return.