lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2008年08月27日

选择或设计实现远程RPC调用所需要考虑的n个方面

Filed under: Hessian,RMI,RPC,XML-RPC — 标签:, , , — lizongbo @ 23:33

选择或设计实现远程RPC调用所需要考虑的n个方面

(前段时间记录的零散片段,却一直没时间仔细整理,仅记录在此,以做备忘。)
可参考协议(组件)为:
http,smtp,pop,ftp,dns,burlap,json,xml-rpc,xmpp,smpp,rmi,soap,hessian,thrift , protocol buffers等等
需要考虑以下方面:

必备条件:
a.多语言支持
b.强大的序列化和反序列化(xml,text,pdu,text+stream)
c.多种传输模式

1.服务端所支持的编程语言。
java,C,C++,C#,PHP等等

2.客户端支持的语言。
java,C,C++,JavaScript等

3.字节流转码。
支持GBK,UTF-8等。

4.支持的基础数据类型。
char,int,long,double,floadt,boolean,List,Map,Object(Struct)

5.同名重载方法区别

6.支持数据包的转发代理 (前端负载均衡)

7.自定义超时连接

8.数据包转换 (对象的序列化和反序列化)

9.数据类型扩展

10.类与接口实现的约束

11.是否支持负载限制 (比如超过100并发时,直接返回系统忙)

12.failover处理

13.事务控制

14.异步调用

15.数据包版本自动识别

16.TCP/UDP支持
(UDP 有1472字节限制。)

17.代码生成器(主要针对数据包的序列化)

18.与现有框架的整合难度(组件化程度)

19.大文件传输

21.数据包序列化效率

客户端连接池
应用范围

22.网络带宽约束(数据包是否支持压缩)

23.服务接口监控统计

数据包加密

SSL支持

是否需要握手消息(是需多次交互还是简单的请求应答模式)

调试抓包的方便性

是否支持双向调用(xmpp支持)

部署难易程度

参数配置难度

是否支持请求队列

请求应答的对应关系

协议可读性

支持客户端并发限制(比如同一ip每秒只能够调用10次)

断点续传和重发数据

URL设置

access.log配置与合并,自定义 logger(用于控制是否打印敏感信息)

过滤器拦截模式

接口代码可读性

常用端口选择

重启服务时的热切换

黏性会话支持(基于IP,或者基于sessionid)

安全端口

是否可以多端口

配置文件

是否能够方便获取真实客户端ip和端口
MDC支持
是否支持线程局部变量(类似webservice获取session,ICE的Current)

防雪崩(提供初始化预热加载)

2008年07月27日

HessianServlet和HessianProxyFactory的配置参数

Filed under: Hessian,RPC — 标签:, — lizongbo @ 14:20

HessianServlet和HessianProxyFactory的配置参数

home-class,service-class,表示Service的实现类的类名

home-api,api-class,是Service的接口类名

object-class,不太了解
object-api,不太了解,

debug,调试开关,默认为false,需要设置为true的时候,值必须是”true”,区分大小写(不建议设置为true)

send-collection-type,设置SerializerFactory是否在序列化的数据里传递集合类的类型名,默认为true,需要设置为false的时候,
值必须是”false”,区分大小写(不建议设置为false)

其实 SerializerFactory还有个 _isAllowNonSerializable属性,控制是否接受对没有实现 java.io.Serializable接口的对象,
通过setAllowNonSerializable来控制,
默认是不接受,为false,而HessianServlet却没提供这个参数的控制开关,因此如果要支持传输没有实现java.io.Serializable接口的对象,
则需要继承HessianServlet来加上相应控制,重载getSerializerFactory方法来设置参数或增加扩展的SerializerFactory,
而无法通过直接配置HessianServlet的初始化参数来实现。

先前提到的 hessian  3.1.5里hession2.0 有bug ,在hessian 3.1.6里依然存在,在hessian 3.2.0中将被修正.

参考: http://maillist.caucho.com/pipermail/hessian-interest/2008-July/000405.html

ServiceContext存放了线程局部变量request,
ServiceContext.getContextRequest()

HessianProxyFactory 设置的 _isOverloadEnabled 可支持同名重载方法。
不过不建议在接口中使用同名方法和变长参数。
_user和_password是设置 http basic认证的用户名和密码。
_isDebug,调试开关
_isHessian2Reply,_isHessian2Request,是否使用hessian 2.0协议发送请求。
_isChunkedPost,设置Chunked编码方式发送请求。

2008年04月12日

hessian 3.1.5的bug及相关例子

Filed under: Hessian,RPC — 标签:, , , — lizongbo @ 22:26

hessian 3.1.5的下载地址在:
http://hessian.caucho.com/download/hessian-3.1.5.jar
http://hessian.caucho.com/download/hessian-3.1.5-src.jar
http://hessian.caucho.com/download/hessian-test.jar

来源: http://hessian.caucho.com/#Java

假如客户端以Hessian2协议进行传输数据,以HessianMetaInfoAPI接口方式调用_hessian_getAttribute方法。
那么com.caucho.hessian.server.HessianSkeleton.java里, 在调用的 第  160行的地方,缺少一句  out.close();

其它几个return的地方,也缺少 out.close();

否则会遇到如下的错误信息

Caused by: com.caucho.hessian.io.HessianProtocolException: expected hessian reply at end of file
?
at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2701)
at com.caucho.hessian.io.Hessian2Input.startReply(Hessian2Input.java:405)
at com.lizongbo.hessian.client.HessianProxy.invoke(HessianProxy.java:65)

独立使用 HessianSkeleton进行处理的时候,

//HessianSkeleton hs=null;
//Hessian2Input h2i=null;

try {
h2i.readCall(); //这行代码非常重要,否则无法正确调用invoke。HessianServlet里有类似的调用
// 对应的是   int code = in.read();
//     int major = in.read();
//      int minor = in.read();

//如果不调用该行代码,则Hessian2Input无法解析出数据包
hs.invoke(h2i, h2o);
} catch (Exception e) {
e.printStackTrace();
}

HessianDebugOutputStream存在bug,如果在HessianServlet开启调试模式,则会抛出异常。

调用出错的接口方法是这样定义的:

public java.sql.Date getDay();
HessianDebugOutputStream的代码比较复杂,由于对hessian协议定义不够熟悉,没找到修正bug的方法。

下面是用mina封装后以TCP方式调用hessian的例子
————–

[code]
package com.lizongbo.hessian.server.handlers;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

import org.apache.mina.common.IoSession;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.server.HessianSkeleton;
import com.lizongbo.hessian.HessianPacketHandler;
import com.lizongbo.hessian.message.HessianCall;
import com.lizongbo.hessian.message.HessianCallResp;
import com.lizongbo.hessian.message.HessianPacket;
import com.lizongbo.hessian.test.Mytest;
import com.lizongbo.hessian.test.Test;
import com.caucho.hessian.io.HessianDebugInputStream;
import java.io.PrintWriter;
import com.caucho.hessian.io.HessianDebugOutputStream;
import com.lizongbo.hessian.BadCommandIDException;

public class HessianCallhandler implements HessianPacketHandler {
private Map<String, HessianSkeleton> hsmap = new HashMap();

public void process(IoSession session, HessianPacket packet) throws
BadCommandIDException {
HessianCall msg = (HessianCall) packet;
if (hsmap.get(msg.getUrl()) == null) {
Test t = new Mytest();
HessianSkeleton hs = new HessianSkeleton(t, Test.class);
hsmap.put(msg.getUrl(), hs);
}

HessianSkeleton hs = hsmap.get(msg.getUrl());
InputStream bai = new ByteArrayInputStream(msg.getCallData());
PrintWriter dbg = new PrintWriter(System.out);
bai = new HessianDebugInputStream(bai, dbg); //增加调试输出,如果不需要调试,则屏蔽该行即可。
Hessian2Input h2i = new Hessian2Input(bai);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
////OutputStream bao2 = new HessianDebugOutputStream(bao, dbg); //增加调试输出,如果不需要调试,则屏蔽该行即可。
Hessian2Output h2o = new Hessian2Output(bao);
try {
h2i.readCall();
hs.invoke(h2i, h2o);
} catch (Exception e) {
e.printStackTrace();
}
HessianCallResp callRes = new HessianCallResp();
callRes.setResData(bao.toByteArray());
session.write(callRes);

}

}

[/code]

Powered by WordPress