Apache Mina: 自定义codec

本文介绍了一个基于Mina框架实现的客户端与服务端通信的例子。具体包括自定义消息对象、编码器与解码器,以及如何在客户端和服务端之间传递这些自定义消息。通过这个例子,读者可以了解到Mina框架的基本使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本例子根据mina自带的例子:sumup改写。

1. 基本原理:
1) 客户端向服务端发送AddMessage对象时,先根据AddMessageEncoder编码, 当服务端接收到AddMessage后,根据自定义的AddMessageDecode解码数据。

2) 服务端数据解码后,生成回复对象ResultMessage,并对该对象通过ResultMessageEncoder进行编码,并发送到客户端。 客户端接收ResultMessage后,根据ResultMessageDecoder解码,并将数据显示出来。

3) AddMessageEncoder,ResultMessageEncoder,AddMessageDecoder,ResultMessageDecoder自定义编码和解码的方法。

2. 代码:
1) 创建AddMessage和ResultMessage对象
AbstractMessage.java

public abstract class AbstractMessage implements Serializable {

private int sequence;

public int getSequence() {
return sequence;
}

public void setSequence(int sequence) {
this.sequence = sequence;
}
}

AddMessage.java

public class AddMessage extends AbstractMessage {

private static final long serialVersionUID = -735205238699949292L;

private int value;

public AddMessage(){

}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

@Override
public String toString() {
return "AddMessage [value=" + value + ", getSequence()="
+ getSequence() + "]";
}

}

ResultMessage.java

public class ResultMessage extends AbstractMessage {

private static final long serialVersionUID = 7431899532938146290L;

private boolean ok;
private int value;

public ResultMessage(){

}

public boolean isOk() {
return ok;
}

public void setOk(boolean ok) {
this.ok = ok;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

@Override
public String toString() {
return "ResultMessage [ok=" + ok + ", value=" + value
+ ", getSequence()=" + getSequence() + "]";
}

}


2) 创建AddMessageEncoder和ResultMessageEncoder
AddMessageEncoder.java

public class AddMessageEncoder<T extends AddMessage> implements MessageEncoder<T> {

@Override
public void encode(IoSession session, T message, ProtocolEncoderOutput out)
throws Exception {

IoBuffer buf = IoBuffer.allocate(16);
buf.setAutoExpand(true); // Enable auto-expand for easier encoding

// Encode a header
buf.putInt(message.getSequence());
buf.putInt(message.getValue());

buf.flip();
out.write(buf);

}

}

ResultMessageEncoder.java

public class ResultMessageEncoder<T extends ResultMessage> implements MessageEncoder<T> {

@Override
public void encode(IoSession session, T message, ProtocolEncoderOutput out)
throws Exception {

IoBuffer buf = IoBuffer.allocate(16);
buf.setAutoExpand(true); // Enable auto-expand for easier encoding


if(message.isOk()){
buf.putShort((short) Constants.RESULT_OK);
buf.putInt(message.getSequence());
buf.putInt(message.getValue());
}else{

buf.putShort((short)Constants.RESULT_ERROR);
buf.putInt(message.getSequence());
buf.putInt(0);
}

buf.flip();
out.write(buf);

}

}


3) 创建AddMessageDecoder和ResultMessageDecoder
AddMessageDecoder.java

public class AddMessageDecoder implements MessageDecoder {


@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {

if (in.remaining() < 1) {
return MessageDecoderResult.NEED_DATA;
}

// Return NOT_OK if not matches.
return MessageDecoderResult.OK;
}

@Override
public MessageDecoderResult decode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {

if (in.remaining() < 1) {
return MessageDecoderResult.NEED_DATA;
}

int sequence = in.getInt();
int value = in.getInt();

AddMessage m = new AddMessage();
m.setSequence(sequence);
m.setValue(value);

out.write(m);

return MessageDecoderResult.OK;


}

@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out)
throws Exception {
// TODO Auto-generated method stub

}

}

ResultMessageDecoder.java

public class ResultMessageDecoder implements MessageDecoder {

@Override
public MessageDecoderResult decodable(IoSession session, IoBuffer in) {

if (in.remaining() < 1) {
return MessageDecoderResult.NEED_DATA;
}

int code = in.getShort();

if(code==Constants.RESULT_OK){
return MessageDecoderResult.OK;
}

// Return NOT_OK if not matches.
return MessageDecoderResult.NOT_OK;
}

@Override
public MessageDecoderResult decode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {

if (in.remaining() < 1) {
return MessageDecoderResult.NEED_DATA;
}

int code = in.getShort();
int sequence = in.getInt();
int value = in.getInt();

ResultMessage m = new ResultMessage();
if(code==Constants.RESULT_OK){
m.setOk(true);
m.setSequence(sequence);
m.setValue(value);
}else{
m.setOk(false);
}

out.write(m);

return MessageDecoderResult.OK;


}

@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out)
throws Exception {
// TODO Auto-generated method stub

}

}


4) 创建CodecFactory,注册AddMessageEncoder, ResultMessageEncoder, AddMessageDecoder, ResultMessageDecoder.

public class DemoProtocolCodecFactory extends DemuxingProtocolCodecFactory {

public DemoProtocolCodecFactory(boolean isServer){
if(isServer){
super.addMessageEncoder(ResultMessage.class, ResultMessageEncoder.class);
super.addMessageDecoder(AddMessageDecoder.class);
}else{
super.addMessageEncoder(AddMessage.class, AddMessageEncoder.class);
super.addMessageDecoder(ResultMessageDecoder.class);
}
}

}


5) 创建server端服务和业务处理ServerIoHandler
Server.java

public class Server {

public void init() throws IOException{

IoAcceptor acceptor = new NioSocketAcceptor();

acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new DemoProtocolCodecFactory(Constants.IS_SERVER)));

acceptor.setHandler(new ServerIoHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);

acceptor.setDefaultLocalAddress(new InetSocketAddress(Constants.PORT));
acceptor.bind();// 启动监听

}


public static void main(String[] args) throws IOException {
Server server = new Server();
server.init();
}

}

ServerIoHandler.java

public class ServerIoHandler extends IoHandlerAdapter {

private static final String SUM_KEY = "sum";

@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
System.out.println(cause.getMessage());
cause.printStackTrace();
session.close(true);
}

@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
AddMessage add = (AddMessage) message;

int sum = ((Integer)session.getAttribute(SUM_KEY)).intValue();
int value = add.getValue();

long total = (long) sum + value;

if(total>Integer.MAX_VALUE || total<Integer.MIN_VALUE){
ResultMessage result = new ResultMessage();
result.setSequence(add.getSequence());
result.setOk(false);
session.write(result);
}else{
sum = (int) total;
session.setAttribute(SUM_KEY, sum);

ResultMessage result = new ResultMessage();
result.setSequence(add.getSequence());
result.setOk(true);
result.setValue(sum);
session.write(result);
}

//System.out.println("total=" + total);
}

@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
session.close(true);
}

@Override
public void sessionOpened(IoSession session) throws Exception {
session.setAttribute(SUM_KEY, new Integer(0));

}
}


6) 创建Client端连接和业务处理ClientIoHandler
Client.java

public class Client {

public void init() throws InterruptedException{
NioSocketConnector connector = new NioSocketConnector();

// Configure the service.
connector.setConnectTimeoutMillis(Constants.CONNECT_TIMEOUT);
connector.getFilterChain().addLast("codec",new ProtocolCodecFilter(new DemoProtocolCodecFactory(!Constants.IS_SERVER)));
connector.getFilterChain().addLast("logger", new LoggingFilter());

connector.setHandler(new ClientIoHandler());

IoSession session;
for (;;) {
try {
ConnectFuture future = connector.connect(new InetSocketAddress(Constants.HOSTNAME, Constants.PORT));
future.awaitUninterruptibly();
session = future.getSession();
break;
} catch (RuntimeIoException e) {
System.err.println("Failed to connect.");
e.printStackTrace();
Thread.sleep(5000);
}
}

// wait until the summation is done
session.getCloseFuture().awaitUninterruptibly();

connector.dispose();
}

/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Client client = new Client();
client.init();

}

}


ClientIoHandler.java

public class ClientIoHandler extends IoHandlerAdapter {

private List<Integer> values = new ArrayList<Integer>();

@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
session.close(true);
}

@Override
public void messageReceived(IoSession session, Object message)
throws Exception {

ResultMessage rm = (ResultMessage) message;
if (rm.isOk()) {

if (rm.getSequence() == values.size() - 1) {
System.out.println("the sum is " + rm.getValue());
session.close(true);
//finished = true;
}
} else {
System.out.println("Server error, disconnecting...");
session.close(true);
//finished = true;
}
}

@Override
public void sessionOpened(IoSession session) throws Exception {

init();

for (int i = 0; i < values.size(); i++) {
int _value = ((Integer) values.get(i)).intValue();

AddMessage m = new AddMessage();
m.setSequence(i);
m.setValue(_value);

session.write(m);
}
}


private void init(){
for(int i=0;i<3;i++){
int _value = i*100 + 1;
values.add(new Integer(_value));
}
}
}

7. Constants.java

public class Constants {
public final static int PORT = 9123;
public static final String HOSTNAME = "localhost";
public static final long CONNECT_TIMEOUT = 30*1000L; // 30 seconds
public final static boolean IS_SERVER = true;
public static final int RESULT_OK = 0;

public static final int RESULT_ERROR = 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值