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

2008年04月3日

在mina的ProtocolDecoder合并 未完整发送的数据包

Filed under: Java — 标签:, — lizongbo @ 19:09

在mina的ProtocolDecoder合并 未完整发送的数据包。

由于Socket方面的基础不扎实,对nio的理解不深入,
这几天看了Apache MINA 2.0.0-M1 里的相关代码,才明白了nio的处理和我先前理解的不一样

虽然在 http://618119.com/archives/2008/03/07/73.html
考虑到了客户端把多个PDU数据包一次发送的情况,却没有考虑到PDU数据包被分片发送的情况,
于是以前写的ProtocolDecoder在网络环境恶劣或客户端没有整包发送数据的情况下,就会出现问题,
在ProtocolDecoder增加了合并PDU数据包的处理,经过测试,PDU数据包分片发送的时候,服务端也能够正常解析了。

客户端往Socket发送数据包的代码:

[code]
byte bo[] = bao.toByteArray();
sc.getOutputStream().write(bo, 0, 4);//先发四个字节
Thread.sleep(500);
sc.getOutputStream().write(bo, 4, 8);//再发送8个字节
Thread.sleep(500);
sc.getOutputStream().write(bo, 12, bo.length – 12);//再把剩余的数据发过去

[/code]

服务端改进后的代码:

[code]
package com.lizongbo.smpp.server.codec;

import org.apache.mina.common.AttributeKey;
import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import com.lizongbo.smpp.BadCommandIDException;
import com.lizongbo.smpp.message.SMPPPacket;
import com.lizongbo.smpp.util.SMPPIO;
import com.lizongbo.smpp.util.PacketFactory;

public class SMPPProtocolDecoder implements ProtocolDecoder {
private static final AttributeKey BUF_BYTE = new AttributeKey(
SMPPProtocolDecoder.class, “bufb”);

public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {
try {
IoBuffer bufTmp = null;
byte[] buf = (byte[]) session.getAttribute(BUF_BYTE);
if (buf == null) {
// System.out.println(“没有尚未处理的数据”);
bufTmp = in;
} else {
// System.out.println(“合并尚未处理的数据”);
bufTmp = IoBuffer.allocate(buf.length + in.remaining());
bufTmp.setAutoExpand(true);
bufTmp.put(buf);
bufTmp.put(in);
bufTmp.flip();
}
while (bufTmp.remaining() >= 4
&& bufTmp.remaining() >= bufTmp.getInt(bufTmp.position())) {// 循环处理数据包
int dataLen = bufTmp.getInt(bufTmp.position());
byte[] b = new byte[dataLen];
bufTmp.get(b);
SMPPPacket pak = null;
int id = -1;
id = SMPPIO.bytesToInt(b, 4, 4);
pak = PacketFactory.newInstance(id);
if (pak != null) {
pak.readFrom(b, 0);
out.write(pak);
}
}
if (bufTmp.hasRemaining()) {// 如果有剩余的数据,则放入Session中
byte[] tmpb = new byte[bufTmp.remaining()];
bufTmp.get(tmpb);
session.setAttribute(BUF_BYTE, tmpb);
}
}

catch (BadCommandIDException ex) {
ex.printStackTrace();
}
}

public void dispose(IoSession session) throws Exception {

}

public void finishDecode(IoSession session, ProtocolDecoderOutput out)
throws Exception {
}

}
[/code]
调试日志如下:
(一个数据包被分为三段发送,服务端收到之后重新组包解析的日志)
Listening on port a 5435
sessionCreated==(0x013E8D89: nio socket, server, /127.0.0.1:1188 => /127.0.0.1:5435)
run decode!!!
in.remaining() == 4
没有不完整数据
数据包长69 bufTmp.remaining() ==4
数据还不完整
剩余数据保存到Session!!!4字节 00:00:00:45
run decode!!!
in.remaining() == 8
尚有不完整数据:00:00:00:45
数据包长69 bufTmp.remaining() ==12
数据还不完整
剩余数据保存到Session!!!12字节 00:00:00:45:80:00:00:00:00:00:00:00
run decode!!!
in.remaining() == 57
尚有不完整数据:00:00:00:45:80:00:00:00:00:00:00:00
数据包长69 bufTmp.remaining() ==69
hexdata:00:00:00:45:80:00:00:00:00:00:00:00:00:00:00:7a
00:00:00:1d:68:74:74:70:3a:2f:2f:31:32:37:2e:30
2e:30:2e:31:3a:35:34:33:35:2f:58:64:70:70:59:61
6e:00:00:00:10:63:02:00:6d:00:04:65:63:68:6f:04
79:79:79:79:7a
(上面是 合并之后得到的数据包)

ps: 也可以使用Apache mina 提供的statemachine来处理类似的问题。

2008年03月7日

Apache MINA 2.0.0-M1 试用体会

Filed under: Java,SSL — 标签:, , , — lizongbo @ 14:15

Apache MINA 2.0.0-M1 的api比1.x更简单好用了,

新增加了许多filter功能,各个filter 功能在filter包下面以子目录方式存放,例如:

org.apache.mina.filter.executor.ExecutorFilter

org.apache.mina.filter.ssl.SslFilter

org.apache.mina.filter.keepalive.KeepAliveFilter

org.apache.mina.filter.compression.CompressionFilter
org.apache.mina.filter.firewall.BlacklistFilter
org.apache.mina.filter.logging.LoggingFilter

[code]

public static void main(String[] args) throws IOException, Exception {
IoAcceptor acceptor = new NioSocketAcceptor();
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
//Utils.addServerSSLSupport(chain);
Utils.addThreadPool(chain);
// Utils.addCompress(chain);
Utils.addCodec(chain);
Utils.addLogger(chain);
SMPPServerSessionHandler handlers = new SMPPServerSessionHandler();
handlers.getHandles().put(Integer.valueOf(0x00000001),
new com.lizongbo.smpp.server.handlers.
BindReceiverHandler());
handlers.getHandles().put(Integer.valueOf(0x00000002),
new com.lizongbo.smpp.server.handlers.
BindTransmitterHandler());
handlers.getHandles().put(Integer.valueOf(0x00000004),
new com.lizongbo.smpp.server.handlers.
SubmitSMHandler());
handlers.getHandles().put(Integer.valueOf(0x00000006),
new com.lizongbo.smpp.server.handlers.
UnbindHandler());
InetSocketAddress serverAddr = new InetSocketAddress(Utils.PORT);
acceptor.setHandler(handlers);
acceptor.bind(serverAddr);
System.out.println(“Listening on port ” + Utils.PORT);
}

[/code]

spring配置的bean也有所变动

[code]

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=”http://www.springframework.org/schema/aop”
xmlns:util=”http://www.springframework.org/schema/util”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd”>
<util:constant id=”ie.omk.smpp.message.BIND_TRANSMITTER”
static-field=”ie.omk.smpp.message.SMPPPacket.BIND_TRANSMITTER” />
<bean id=”com.lizongbo.smpp.server.handlers.BindTransmitterHandler”
class=”com.lizongbo.smpp.server.handlers.BindTransmitterHandler” />
<bean id=”com.lizongbo.smpp.server.handlers.BindReceiverHandler”
class=”com.lizongbo.smpp.server.handlers.BindReceiverHandler” />
<bean id=”com.lizongbo.smpp.server.handlers.SubmitSMHandler”
class=”com.lizongbo.smpp.server.handlers.SubmitSMHandler” />
<bean id=”com.lizongbo.smpp.server.handlers.UnbindHandler”
class=”com.lizongbo.smpp.server.handlers.UnbindHandler” />
<util:map id=”handlers” key-type=”java.lang.Integer”>
<entry key=”0x00000002″>
<ref
local=”com.lizongbo.smpp.server.handlers.BindTransmitterHandler” />
</entry>
<entry key=”0x00000001″>
<ref
local=”com.lizongbo.smpp.server.handlers.BindReceiverHandler” />
</entry>
<entry key=”0x00000004″>
<ref
local=”com.lizongbo.smpp.server.handlers.SubmitSMHandler” />
</entry>
<entry key=”0x00000006″>
<ref
local=”com.lizongbo.smpp.server.handlers.UnbindHandler” />
</entry>
</util:map>
<bean
class=”org.springframework.beans.factory.config.CustomEditorConfigurer”>
<property name=”customEditors”>
<map>
<entry key=”java.net.SocketAddress”>
<bean
class=”org.apache.mina.integration.beans.InetSocketAddressEditor” />
</entry>
</map>
</property>
</bean>
<!– The IoHandler delegate implementation –>
<bean id=”smppHandler”
class=”com.lizongbo.smpp.server.SMPPServerSessionHandler”>
<property name=”handles”>
<ref local=”handlers” />
</property>
<property name=”readerIdleTimeout”>
<value>600</value>
</property>
</bean>
<!– The protocol codec factory for smpp –>
<bean id=”smppProtocolCodecFactory”
class=”com.lizongbo.smpp.server.codec.SMPPProtocolCodecFactory”>
</bean>
<util:map id=”mfilters” key-type=”java.lang.String”
value-type=”org.apache.mina.common.IoFilter”
map-class=”java.util.LinkedHashMap”>
<entry key=”threadpool”>
<bean
class=”org.apache.mina.filter.executor.ExecutorFilter” />
</entry>
<!– entry key=”compress”>
<bean
class=”org.apache.mina.filter.compression.CompressionFilter” />
</entry–>
<entry key=”codec”>
<bean
class=”org.apache.mina.filter.codec.ProtocolCodecFilter”>
<constructor-arg ref=”smppProtocolCodecFactory” />
</bean>
</entry>
<entry key=”logger”>
<bean class=”org.apache.mina.filter.logging.LoggingFilter” />
</entry>
</util:map>
<bean id=”smppFilterChainBuilder”
class=”org.apache.mina.common.DefaultIoFilterChainBuilder”>
<property name=”filters” ref=”mfilters” />
</bean>
<util:list id=”ipaddrs” value-type=”java.net.InetSocketAddress”>
<value>0.0.0.0:5432</value>
<value>0.0.0.0:5433</value>
</util:list>
<bean id=”smppAcceptor”
class=”org.apache.mina.transport.socket.nio.NioSocketAcceptor”>
<property name=”filterChainBuilder”
ref=”smppFilterChainBuilder” />
<property name=”handler” ref=”smppHandler” />
<property name=”defaultLocalAddresses” ref=”ipaddrs” />
</bean>

</beans>
[/code]

在修改代码的时候,发现以前写的smpp server例子里SMPPProtocolDecoder 存在bug,

[code]
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {

try {

//以前用的if判断,导致有数据包漏了。

while(in.remaining() >= 4
&& (in.remaining() >= in.getInt(in.position()))) {
byte[] b = new byte[in.getInt(in.position())];
in.get(b);
SMPPPacketpak = null;
int id = -1;
id = SMPPIO.bytesToInt(b, 4, 4);
pak = PacketFactory.newInstance(id);
if (pak != null) {
pak.readFrom(b, 0);
System.out.println(“decode:==” + pak);
out.write(pak);
}
}
} catch (BadCommandIDException ex) {
ex.printStackTrace();
}
}

[/code]

在使用AprSocketAcceptor的时候,客户端连接上来时,

服务端就出错,在网上也没搜索到这个错误码具体是什么含义。

[code]

java.io.IOException: (乱码显示) (code: -730054)
at org.apache.mina.transport.socket.apr.AprIoProcessor.throwException(AprIoProcessor.java:365)
at org.apache.mina.transport.socket.apr.AprIoProcessor.write(AprIoProcessor.java:352)
at org.apache.mina.transport.socket.apr.AprIoProcessor.write(AprIoProcessor.java:1)
at org.apache.mina.common.AbstractPollingIoProcessor.writeBuffer(AbstractPollingIoProcessor.java:567)
at org.apache.mina.common.AbstractPollingIoProcessor.flushNow(AbstractPollingIoProcessor.java:528)
at org.apache.mina.common.AbstractPollingIoProcessor.flush(AbstractPollingIoProcessor.java:469)
at org.apache.mina.common.AbstractPollingIoProcessor.access$500(AbstractPollingIoProcessor.java:43)
at org.apache.mina.common.AbstractPollingIoProcessor$Worker.run(AbstractPollingIoProcessor.java:681)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)

[/code]

2008年02月25日

几种短信协议

Filed under: Java — 标签:, , — lizongbo @ 09:32

几种短信协议:

1.SMPP 国际标准 3.3, 3.4, 5.0

以下是中国特色的协议标准:
2.CMPP 中国移动 2.0, 3.0
3.SMGP 中国电信 1.3, 2.0, 3.0
4.SGIP 中国联通 1.2
5.CNGP 中国网通 2.0
6.PTOP 点对点短消息网间互通协议  3.0

Older Posts »

Powered by WordPress