Protocol Buffers没有提供RPC的具体实现。不过,你可以在 http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns 找到一些第三方开发的RPC实现。
本文尝试了http RPC的实现,运行在Tomcat的servlet中。需要注意的是,这只是个测试,实现是不完整的,并且代码很不好看,很不好复用。
主要参考: http://www.eishay.com/2008/11/protobuf-vs-spring-rpc.html
1、定义协议格式
user.proto
- package mytest;
- option java_package = "mytest.protobuf.gen";
- option java_outer_classname = "UserProtos";
- message User {
- required string name = 1;
- required int32 userId = 2;
- required string loginName = 3;
- required string password = 4;
- }
- message UserId {
- required int32 userId = 1;
- }
- service UserService {
- rpc getUser (UserId) returns (User);
- }
2、生成java代码
protoc --java_out=gen user.proto
3、服务端代码
3.1 服务的实现
- package myserver;
- import com.google.protobuf.RpcCallback;
- import com.google.protobuf.RpcController;
- import mytest.protobuf.gen.UserProtos.User;
- import mytest.protobuf.gen.UserProtos.UserId;
- import mytest.protobuf.gen.UserProtos.UserService;
- public class UserServiceHandler extends UserService {
- @Override
- public void getUser(RpcController controller, UserId request,
- RpcCallback<User> done) {
- User.Builder user = User.newBuilder();
- user.setUserId(100);
- user.setLoginName("login1");
- user.setPassword("pwd1");
- user.setName("user1");
- done.run(user.build());
- }
- }
3.2 servlet
- package servlet;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import myserver.UserServiceHandler;
- import mytest.protobuf.gen.UserProtos.User;
- import mytest.protobuf.gen.UserProtos.UserId;
- import com.google.protobuf.RpcCallback;
- public class UserServiceServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- private UserServiceHandler _handler = new UserServiceHandler();
- @Override
- protected void doGet(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- PrintWriter w = response.getWriter();
- w.write("This is a protocal buffer service!");
- w.close();
- }
- @Override
- protected void doPost(HttpServletRequest request,
- final HttpServletResponse response) throws ServletException, IOException {
- RpcCallback<User> done = new RpcCallback<User>() {
- DataOutputStream dos = new DataOutputStream(response.getOutputStream());
- public void run(User user) {
- try {
- byte[] array = user.toByteArray();
- dos.writeInt(array.length);
- dos.write(array);
- dos.flush();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- };
- DataInputStream dis = new DataInputStream(request.getInputStream());
- byte[] array = new byte[dis.readInt()];
- dis.readFully(array);
- UserId req = UserId.parseFrom(array);
- _handler.getUser(null, req, done);
- }
- }
3.3 web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app id="WebApp_ID" version="2.4"
- xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
- <display-name>protobuf</display-name>
- <servlet>
- <servlet-name>UserServiceServlet</servlet-name>
- <servlet-class>servlet.UserServiceServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>UserServiceServlet</servlet-name>
- <url-pattern>/UserService</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>index.html</welcome-file>
- <welcome-file>index.htm</welcome-file>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
4、客户端代码
- package myclient;
- import java.io.ByteArrayOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import mytest.protobuf.gen.UserProtos.User;
- import mytest.protobuf.gen.UserProtos.UserId;
- import mytest.protobuf.gen.UserProtos.UserService;
- import org.apache.commons.httpclient.HttpClient;
- import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
- import org.apache.commons.httpclient.methods.PostMethod;
- import com.google.protobuf.Message;
- import com.google.protobuf.RpcCallback;
- import com.google.protobuf.RpcChannel;
- import com.google.protobuf.RpcController;
- import com.google.protobuf.Descriptors.MethodDescriptor;
- public class ClientByHttp {
- public static void main(String[] args) {
- final HttpClient client = new HttpClient();
- RpcChannel channel = new RpcChannel()
- {
- public void callMethod (MethodDescriptor method,
- RpcController controller,
- Message request,
- Message responsePrototype,
- RpcCallback<Message> done)
- {
- try
- {
- System.out.println("calling");
- PostMethod post = new PostMethod("http://localhost:8080/UserService");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(baos);
- //dos.writeInt(method<mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js"></mce:script><mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js"></mce:script>.getIndex());
- byte[] array = request.toByteArray();
- dos.writeInt(array.length);
- dos.write(array);
- dos.flush();
- byte[] toSend = baos.toByteArray();
- System.out.println("sending size = " + toSend.length);
- post.setRequestEntity(new ByteArrayRequestEntity(toSend ));
- client.executeMethod(post);
- DataInputStream dis = new DataInputStream(post.getResponseBodyAsStream());
- int size = dis.readInt();
- array = new byte[size];
- dis.readFully(array);
- done.run(responsePrototype.newBuilderForType().mergeFrom(array).build());
- System.out.println("done");
- post.releaseConnection();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- };
- UserService service = UserService.newStub(channel);
- UserId.Builder userId = UserId.newBuilder();
- userId.setUserId(1);
- RpcCallback<User> done = new RpcCallback<User>()
- {
- public void run (User user)
- {
- System.out.println("name=" + user.getName());
- System.out.println("loginname=" + user.getLoginName());
- System.out.println("password=" + user.getPassword());
- }
- };
- service.getUser(null, userId.build(), done);
- }
- }