Mina实现自定义协议的通信
来源:互联网 发布:罗马军团到中国 知乎 编辑:程序博客网 时间:2024/05/16 00:57
转http://www.open-open.com/lib/view/open1351557171910.html
网络的传输使用需要遵循一定的规则,这些规则我们称为协议。如在互联网请求HTML页面的时候,我们要遵循HTTP协议,HTTP头的格式就是我们要遵守的规则:
01
Request Headers
02
Accept:
03
text/html,application/xhtml+xml,application/xml;q=
0.9
,*/*;q=
0.8
04
Accept-Charset:
05
GBK,utf-
8
;q=
0.7
,*;q=
0.3
06
Accept-Encoding:
07
gzip,deflate,sdch
08
Accept-Language:
09
zh-CN,zh;q=
0.8
10
Cache-Control:
11
max-age=
0
比如我们在做一些第三方开发的时候,经常会按照固定的格式向服务器端发送请求,服务器验证消息后,返回相应的结果。在Mina的开发中,我们也会用到这种模式。首先我们先来描述下这种方式的使用情形:
这样的方式,目前,我所在的项目组中主要用于通信和传输。为了将文件从客户端传到云端,我们先在客户端将数据根据一定的规则切片,然后通过一种特定的格式传输到服务器端。Mina,作为这中间的桥梁,秉承了框架很好的优点,快速开发。由于我们的服务器端采用的是C写的,所以我只给出客户端的编码过程,解码过程原理和开发都一样。
用Mina执行一定协议的传输,主要有以下几个步骤:
1. 设计通信协议;
2. 编写请求(返回)对象和业务对象;
3. 编写解码(编码)器;
4. 编写客户端、服务器端。
下面根据代码,一步步介绍这个过程,由于是前提的测试代码,所以没有考虑线程安全等问题,只是一个思路:
首先是通信的协议,根据mina的构建规则,将协议设计成抽象类,由请求对象和返回对象分别去继承,协议格式如下:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
04
import
org.apache.mina.core.buffer.IoBuffer;
05
06
/**
07
* 通信协议
08
* @author Chen.Hui
09
*
10
*/
11
public
abstract
class
AbsMessage {
12
13
/**
14
* 协议格式:
15
*
16
* tag | header length | Filename | File length | offset | checksum | temps | data
17
*
18
*/
19
20
/** 请求或访问类型 请求Tag:0x00 返回Tag:0x01 共 8 bit */
21
public
abstract
byte
getTag();
22
23
/** 头文件长度 共 2^16 可表示 65535 */
24
public
abstract
short
getHeaderlen();
25
26
/** 根据UUID生成文件唯一标识,共 8*36=288 bit */
27
public
abstract
byte
[] getFilename();
//需要設計一個算法
28
29
/** 获取文件长度 2^32=4GB 共 32 bit */
30
public
abstract
int
getFileLen();
31
32
/** 获取文件的偏移量offset 共 32 bit */
33
public
abstract
int
getOffset();
34
35
/** 获取文件的MD5校验码 共 32 bit */
36
public
abstract
byte
[] getChecksum();
37
38
/** 预留字段 长度不超过 128 bit */
39
public
abstract
byte
[] getTmp();
40
41
/**data 方式传输内容 不超过1024bit*/
42
public
abstract
IoBuffer getData();
43
44
}
下面是请求对象(返回)和业务对象,这里的业务对象主要功能是将文件切片:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.io.IOException;
04
import
java.nio.charset.Charset;
05
06
import
org.apache.mina.core.buffer.IoBuffer;
07
import
org.slf4j.Logger;
08
import
org.slf4j.LoggerFactory;
09
10
/**
11
* 请求对象
12
*
13
* @author Chen.Hui
14
*
15
*/
16
public
class
InfoRequest
extends
AbsMessage {
17
18
Logger logger = LoggerFactory.getLogger(InfoRequest.
class
);
19
20
FilePiece piece;
21
22
Charset charset;
23
24
public
InfoRequest(FilePiece piece) {
25
this
.piece = piece;
26
}
27
28
public
InfoRequest(){
29
//empty
30
}
31
32
@Override
33
public
byte
getTag() {
// 0x01 请求包
34
return
(
byte
)
0x01
;
35
}
36
37
@Override
38
public
short
getHeaderlen() {
39
if
(getTmp() ==
null
) {
40
short
len = (
short
) (
1
+
2
+
36
+
4
+
4
+
4
);
41
return
len;
42
}
else
{
43
short
len = (
short
) (
1
+
2
+
36
+
4
+
4
+
4
+ (
short
) getTmp().length);
44
return
len;
45
}
46
}
47
48
@Override
49
public
int
getFileLen() {
// 文件总长度
50
51
try
{
52
return
(
int
) piece.getFc().size();
53
54
}
catch
(IOException e) {
55
e.printStackTrace();
56
}
57
return
0
;
58
}
59
60
@Override
61
public
int
getOffset() {
// 传输 偏移量
62
63
return
piece.getOffset();
64
65
}
66
67
@Override
68
public
byte
[] getFilename() {
// 文件名称
69
70
/** check the bits of name */
71
byte
[] name =
new
byte
[
36
];
72
name = piece.getFilename().getBytes();
73
74
return
name;
75
76
}
77
78
@Override
79
public
byte
[] getChecksum() {
// checksum
80
81
byte
[] checksum =
new
byte
[
4
];
82
checksum = piece.getChecksum().getBytes();
83
return
checksum;
84
}
85
86
@Override
87
public
byte
[] getTmp() {
88
byte
[] b=
new
byte
[
5
];
89
return
b;
90
}
91
92
@Override
93
public
IoBuffer getData() {
94
return
piece.getBuf();
95
}
96
}
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.io.File;
04
import
java.io.RandomAccessFile;
05
import
java.nio.ByteBuffer;
06
import
java.nio.channels.FileChannel;
07
import
java.util.UUID;
08
09
import
org.apache.mina.core.buffer.IoBuffer;
10
import
org.slf4j.Logger;
11
import
org.slf4j.LoggerFactory;
12
13
/**
14
* 分片文件操作类
15
*
16
* @author Chen.Hui
17
*
18
*/
19
public
class
FilePiece {
20
21
Logger logger = LoggerFactory.getLogger(FilePiece.
class
);
22
23
private
ByteBuffer[] dsts;
24
25
private
IoBuffer buf;
26
27
private
String filename;
28
29
private
FileChannel fc;
30
31
private
RandomAccessFile raf;
32
33
private
int
offset;
34
35
private
String checksum;
36
37
/** 构建文件的基本信息 */
38
public
FilePiece(String path,
int
offset)
throws
Exception {
39
40
raf =
new
RandomAccessFile(
new
File(path),
"rw"
);
41
fc = raf.getChannel();
42
43
this
.offset = offset;
44
45
dsts =
new
ByteBuffer[
1024
];
46
47
for
(
int
i =
0
; i < dsts.length; i++) {
48
dsts[i] = ByteBuffer.allocate(
1024
);
49
}
50
51
fc.read(dsts, offset,
1024
);
52
53
54
buf=IoBuffer.allocate(
1024
);
55
56
filename = UUID.randomUUID().toString();
57
logger.info(
"has built:"
+ filename +
" filename size"
58
+ filename.length());
59
60
}
61
/**这个方法还有点儿问题,数据取的不对*/
62
public
IoBuffer getBuf(){
63
dsts[
0
].flip();
64
while
(dsts[
0
].hasRemaining()){
65
buf.putChar(dsts[
0
].getChar());
66
}
67
buf.flip();
68
return
buf;
69
}
70
71
public
String getFilename() {
72
return
filename;
73
}
74
75
public
FileChannel getFc() {
76
return
fc;
77
}
78
79
public
RandomAccessFile getRaf() {
80
return
raf;
81
}
82
83
public
int
getOffset() {
84
return
offset;
85
}
86
87
public
String getChecksum() {
88
// TODO checksum algorithems
89
return
"aaaa"
;
90
}
91
}
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.nio.charset.Charset;
04
05
import
org.apache.mina.core.buffer.IoBuffer;
06
import
org.apache.mina.core.session.IoSession;
07
import
org.apache.mina.filter.codec.ProtocolEncoderOutput;
08
import
org.apache.mina.filter.codec.demux.MessageEncoder;
09
10
/**
11
* 编码器
12
* @author Chen.Hui
13
*
14
*/
15
public
class
InfoEncoder
implements
MessageEncoder<absmessage>{
16
17
private
Charset charset;
18
19
public
InfoEncoder(Charset charset){
20
this
.charset=charset;
21
}
22
23
@Override
24
public
void
encode(IoSession session, AbsMessage message,
25
ProtocolEncoderOutput out)
throws
Exception {
26
27
IoBuffer buf=IoBuffer.allocate(
1024
).setAutoExpand(
true
);
28
29
if
(message
instanceof
InfoRequest){
30
31
InfoRequest req=(InfoRequest) message;
32
buf.put(req.getTag());
33
buf.putShort((
short
)req.getHeaderlen());
34
buf.put(req.getFilename());
35
buf.putInt(req.getFileLen());
36
buf.putInt(req.getOffset());
37
buf.put(req.getChecksum());
38
buf.put(req.getTmp());
39
buf.put(req.getData());
40
41
}
else
if
(message
instanceof
InfoResponse){
42
//TODO
43
}
44
45
buf.flip();
46
47
out.write(buf);
48
}
49
}</absmessage>
解码器与之类似,解码器在这里的作用主要用户服务器端解码:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.nio.charset.Charset;
04
05
import
org.apache.mina.core.buffer.IoBuffer;
06
import
org.apache.mina.core.session.IoSession;
07
import
org.apache.mina.filter.codec.ProtocolDecoderOutput;
08
import
org.apache.mina.filter.codec.demux.MessageDecoder;
09
import
org.apache.mina.filter.codec.demux.MessageDecoderResult;
10
/**
11
* 解码器
12
* @author ChenHui
13
*
14
*/
15
public
class
InfoDecoder
implements
MessageDecoder {
16
17
private
Charset charset;
18
19
public
InfoDecoder(Charset charset) {
20
this
.charset = charset;
21
}
22
23
@Override
24
public
MessageDecoderResult decodable(IoSession session, IoBuffer in) {
25
26
//System.out.println("package size:"+in.remaining());
27
// 报头长度<56
28
if
(in.remaining() <
56
) {
29
return
MessageDecoderResult.NEED_DATA;
30
}
31
32
byte
tag = in.get();
33
short
head_len=in.getShort();
34
35
if
(tag == (
short
)
0x01
) {
36
System.out.println(
"请求标识符:"
+tag+
" head length:"
+head_len);
37
}
else
{
38
//System.out.println("未知标识符...");
39
return
MessageDecoderResult.NOT_OK;
40
}
41
42
return
MessageDecoderResult.OK;
43
}
44
45
@Override
46
public
MessageDecoderResult decode(IoSession session, IoBuffer in,
47
ProtocolDecoderOutput out)
throws
Exception {
48
byte
tag=in.get();
49
50
if
(tag==
0x01
){
51
InfoReqContainer irc=
new
InfoReqContainer();
52
irc.setTag(tag);
53
irc.setHeadlen(in.getShort());
54
irc.setFilename(in.getString(
36
, charset.newDecoder()));
55
irc.setFilelen(in.getInt());
56
irc.setOffset(in.getInt());
57
irc.setChecksum(in.getString(
4
, charset.newDecoder()));
58
irc.setTemp(in.getString(
5
, charset.newDecoder()));
//应该用head len-53
59
irc.setData(in);
60
61
out.write(irc);
62
}
63
64
return
MessageDecoderResult.OK;
65
}
66
67
@Override
68
public
void
finishDecode(IoSession session, ProtocolDecoderOutput out)
69
throws
Exception {
70
// TODO Auto-generated method stub
71
72
}
73
74
}
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
org.apache.mina.core.buffer.IoBuffer;
04
05
/**
06
* 请求对象解析类
07
*
08
* @author Chen.Hui
09
*
10
*/
11
public
class
InfoReqContainer {
12
private
byte
tag;
13
private
short
headlen;
14
private
String filename;
15
private
int
filelen;
16
private
int
offset;
17
private
String temp;
18
private
String checksum;
19
private
IoBuffer data;
20
21
public
byte
getTag() {
22
return
tag;
23
}
24
25
public
void
setTag(
byte
tag) {
26
this
.tag = tag;
27
}
28
29
public
short
getHeadlen() {
30
return
headlen;
31
}
32
33
public
void
setHeadlen(
short
headlen) {
34
this
.headlen = headlen;
35
}
36
37
public
String getFilename() {
38
return
filename;
39
}
40
41
public
void
setFilename(String filename) {
42
this
.filename = filename;
43
}
44
45
public
int
getFilelen() {
46
return
filelen;
47
}
48
49
public
void
setFilelen(
int
filelen) {
50
this
.filelen = filelen;
51
}
52
53
public
int
getOffset() {
54
return
offset;
55
}
56
57
public
void
setOffset(
int
offset) {
58
this
.offset = offset;
59
}
60
61
public
String getTemp() {
62
return
temp;
63
}
64
65
public
void
setTemp(String temp) {
66
this
.temp = temp;
67
}
68
69
public
String getChecksum() {
70
return
checksum;
71
}
72
73
public
void
setChecksum(String checksum) {
74
this
.checksum = checksum;
75
}
76
77
public
IoBuffer getData() {
78
return
data;
79
}
80
81
public
void
setData(IoBuffer data) {
82
this
.data = data;
83
}
84
85
}
在mina中,要将解码器和编码器绑定到协议工厂类中,才能被过滤器使用:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory;
04
import
org.apache.mina.filter.codec.demux.MessageDecoder;
05
import
org.apache.mina.filter.codec.demux.MessageEncoder;
06
07
public
class
InfoCodecFactory
extends
DemuxingProtocolCodecFactory {
08
private
MessageDecoder decoder;
09
10
private
MessageEncoder<absmessage> encoder;
11
12
public
InfoCodecFactory(MessageDecoder decoder,
13
MessageEncoder<absmessage> encoder) {
14
this
.decoder = decoder;
15
this
.encoder = encoder;
16
addMessageDecoder(
this
.decoder);
17
addMessageEncoder(AbsMessage.
class
,
this
.encoder);
18
}
19
}</absmessage></absmessage>
做完了这些,编码解码的工作都完成了,最后就是写客户端和服务器端进行测试,注意文件位置,这里没有做提示:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.net.InetSocketAddress;
04
import
java.nio.charset.Charset;
05
06
import
org.apache.mina.core.future.ConnectFuture;
07
import
org.apache.mina.core.service.IoConnector;
08
import
org.apache.mina.core.session.IoSession;
09
import
org.apache.mina.filter.codec.ProtocolCodecFilter;
10
import
org.apache.mina.transport.socket.nio.NioSocketConnector;
11
12
public
class
TestClient {
13
14
private
static
String HOST =
"127.0.0.1"
;
15
16
private
static
int
PORT =
8082
;
17
18
public
static
void
main(String[] args) {
19
// 创建一个非阻塞的客户端程序
20
IoConnector connector =
new
NioSocketConnector();
21
// 设置链接超时时间
22
connector.setConnectTimeout(
30000
);
23
// 添加过滤器
24
connector.getFilterChain().addLast(
25
"codec"
,
26
new
ProtocolCodecFilter(
new
InfoCodecFactory(
27
new
InfoDecoder(Charset.forName(
"utf-8"
)),
28
new
InfoEncoder(Charset.forName(
"utf-8"
)))));
29
// 添加业务逻辑处理器类
30
connector.setHandler(
new
ClientHandler());
31
IoSession session =
null
;
32
try
{
33
ConnectFuture future = connector.connect(
new
InetSocketAddress(
34
HOST, PORT));
// 创建连接
35
future.awaitUninterruptibly();
// 等待连接创建完成
36
session = future.getSession();
// 获得session
37
38
FilePiece piece =
new
FilePiece(
39
"D:\\Develop Libs Tar\\apache-mina-2.0.7-bin.zip"
,
0
);
40
41
InfoRequest ir =
new
InfoRequest(piece);
42
43
session.write(ir);
// 发送消息
44
45
46
}
catch
(Exception e) {
47
e.printStackTrace();
48
System.out.println(
"客户端链接异常..."
);
49
}
50
51
session.getCloseFuture().awaitUninterruptibly();
// 等待连接断开
52
connector.dispose();
53
}
54
55
}
客户端的Handler没有做任何处理:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
org.apache.mina.core.service.IoHandler;
04
import
org.apache.mina.core.session.IdleStatus;
05
import
org.apache.mina.core.session.IoSession;
06
07
public
class
ClientHandler
implements
IoHandler {
08
09
@Override
10
public
void
sessionCreated(IoSession session)
throws
Exception {
11
// TODO Auto-generated method stub
12
13
}
14
15
@Override
16
public
void
sessionOpened(IoSession session)
throws
Exception {
17
// TODO Auto-generated method stub
18
19
}
20
21
@Override
22
public
void
sessionClosed(IoSession session)
throws
Exception {
23
// TODO Auto-generated method stub
24
25
}
26
27
@Override
28
public
void
sessionIdle(IoSession session, IdleStatus status)
29
throws
Exception {
30
// TODO Auto-generated method stub
31
32
}
33
34
@Override
35
public
void
exceptionCaught(IoSession session, Throwable cause)
36
throws
Exception {
37
// TODO Auto-generated method stub
38
39
}
40
41
@Override
42
public
void
messageReceived(IoSession session, Object message)
43
throws
Exception {
44
//System.out.println(message.toString());
45
}
46
47
@Override
48
public
void
messageSent(IoSession session, Object message)
throws
Exception {
49
// TODO Auto-generated method stub
50
51
}
52
53
}
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
java.net.InetSocketAddress;
04
import
java.nio.charset.Charset;
05
06
import
org.apache.mina.core.service.IoAcceptor;
07
import
org.apache.mina.core.session.IdleStatus;
08
import
org.apache.mina.core.session.IoSessionConfig;
09
import
org.apache.mina.filter.codec.ProtocolCodecFilter;
10
import
org.apache.mina.filter.logging.LogLevel;
11
import
org.apache.mina.filter.logging.LoggingFilter;
12
import
org.apache.mina.transport.socket.nio.NioSocketAcceptor;
13
14
15
16
public
class
TestServer{
17
18
private
static
int
PORT =
8082
;
19
20
public
static
void
main(String[] args) {
21
IoAcceptor acceptor =
null
;
22
try
{
23
// 创建一个非阻塞的server端的Socket
24
acceptor =
new
NioSocketAcceptor();
25
26
// 设置过滤器(添加自带的编解码器)
27
acceptor.getFilterChain().addLast(
28
"codec"
,
29
new
ProtocolCodecFilter(
new
InfoCodecFactory(
30
new
InfoDecoder(Charset.forName(
"utf-8"
)),
31
new
InfoEncoder(Charset.forName(
"utf-8"
)))));
32
// 设置日志过滤器
33
LoggingFilter lf =
new
LoggingFilter();
34
lf.setMessageReceivedLogLevel(LogLevel.DEBUG);
35
acceptor.getFilterChain().addLast(
"logger"
, lf);
36
// 获得IoSessionConfig对象
37
IoSessionConfig cfg = acceptor.getSessionConfig();
38
// 读写通道10秒内无操作进入空闲状态
39
cfg.setIdleTime(IdleStatus.BOTH_IDLE,
100
);
40
41
// 绑定逻辑处理器
42
acceptor.setHandler(
new
ServerHandler());
43
// 绑定端口
44
acceptor.bind(
new
InetSocketAddress(PORT));
45
System.out.println(
"成功开启服务器端..."
);
46
47
}
catch
(Exception e) {
48
49
e.printStackTrace();
50
}
51
}
52
}
服务器端的Handler:
01
package
com.a2.desktop.example5.mina.potocol;
02
03
import
org.apache.mina.core.service.IoHandler;
04
import
org.apache.mina.core.session.IdleStatus;
05
import
org.apache.mina.core.session.IoSession;
06
07
public
class
ServerHandler
implements
IoHandler {
08
09
@Override
10
public
void
sessionCreated(IoSession session)
throws
Exception {
11
// TODO Auto-generated method stub
12
13
}
14
15
@Override
16
public
void
sessionOpened(IoSession session)
throws
Exception {
17
// TODO Auto-generated method stub
18
19
}
20
21
@Override
22
public
void
sessionClosed(IoSession session)
throws
Exception {
23
// TODO Auto-generated method stub
24
25
}
26
27
@Override
28
public
void
sessionIdle(IoSession session, IdleStatus status)
29
throws
Exception {
30
// TODO Auto-generated method stub
31
32
}
33
34
@Override
35
public
void
exceptionCaught(IoSession session, Throwable cause)
36
throws
Exception {
37
// TODO Auto-generated method stub
38
39
}
40
41
@Override
42
public
void
messageReceived(IoSession session, Object message)
43
throws
Exception {
44
if
(message
instanceof
InfoReqContainer) {
45
InfoReqContainer irc = (InfoReqContainer) message;
46
System.out.println(
"服务器端 获取成功 Tag:"
+ irc.getTag() +
"\r\n "
+
"head len:"
47
+ irc.getHeadlen() +
"\r\nfilename: "
+ irc.getFilename()
48
+
"\r\nfile len:"
+irc.getFilelen()+
"\r\noffset:"
+irc.getOffset()+
"\r\nchecksum:"
+irc.getChecksum()+
"\r\ndata:"
+irc.getData().toString());
49
50
session.write(
"success rescive"
);
51
52
}
else
{
53
System.out.println(
"获取失败"
);
54
}
55
56
}
57
58
@Override
59
public
void
messageSent(IoSession session, Object message)
throws
Exception {
60
// TODO Auto-generated method stub
61
62
}
63
64
}
- Mina实现自定义协议的通信
- Mina实现自定义协议的通信
- Mina实现自定义协议的通信
- Mina实现自定义协议的通信
- Java - Apache Mina 自定义协议通信
- Mina自定义协议-实现数据交互
- Mina 2 编码解码协议 及 已经实现通信的完整代码
- Apache Mina 自定义协议
- apache mina 自定义协议
- 用MINA实现UDP通信的例子
- MINA通信deCode实现
- MINA通信enCode实现
- 使用SuperSocket实现TLV自定义协议网络通信的Demo
- Android 使用Mina的Nio实现客户端服务器通信
- mina仿qq聊天功能,自定义协议,协议的编码和解码详解,发送xml对象json,mina开发大全,详细api,mina心跳
- Mina学习(三):实现简单自定义协议包(报文)
- java: java mina ——基于TCP/IP、UDP/IP协议栈的通信框架
- 自定义协议通信
- 11137 - Ingenuous Cubrency
- C++中继承技术引发的问题:重载(overload),覆盖(override)和隐藏(hide)的区别
- Code Sign error: Provisioning profile '6805769A-5085-4BE7-B9D1-2859CD2CBE9E' can't be found
- 硬件公司构建平台战略的思考
- 如何校正使用笔记本电脑电池?
- Mina实现自定义协议的通信
- 使用ajax让session永不过期
- HTML CSS 概要
- C++中的模板比较容易混淆的几个概念:类模板和类成员模板以及函数模板
- 键盘的inputAccessoryView属性
- 熊绎:我看软件工程师的职业规划
- 【如何隐藏windows 7的登录账号】
- JS---- 图片由灰色变彩色(默认显示为灰色)。IE6为彩色
- cool edit pro 2.1中文版未定义外部错误怎么解决