1.下载包:
Mina下载页:http://mina.apache.org/downloads-mina.html
快速下载链接:http://mirrors.cnnic.cn/apache/mina/mina/2.0.16/apache-mina-2.0.16-bin.tar.gz
将下载好的包解压出来,将dist/mina-core-2.0.16.jar和lib/slf4j-api-1.7.21.jar拷贝到工程目录中,进入Project Structure->Dependencies将这两个jar包添加为新的File Dependency。
java api doc:http://mina.apache.org/mina-project/apidocs/index.html
2.配置相关参数
长连接
private static Boolean Closed = false;
private static NioSocketConnector connector;
private static IoSession session;
private void init() {
connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
//配置日志
connector.getFilterChain().addLast("logger", new LoggingFilter());
//配置解码器与编码器
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new AppProtocolCodecFactory()));
//配置数据返回处理
connector.setHandler(new AppSocketIoHandler());
//设置接收缓存区大小
connector.getSessionConfig().setReceiveBufferSize(65536);//读取缓冲去大小最大65536,64KB
connector.getSessionConfig().setMinReadBufferSize(1024*64);//读取缓冲去大小最大65536,64KB
//设置心跳工程
KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
当读操作空闲时发送心跳
KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory);
// 设置心跳包请求后超时无反馈情况下的处理机制,默认为关闭连接,在此处设置为输出日志提醒
heartBeat.setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler.LOG);
/** 是否回发 */
heartBeat.setForwardEvent(false);
/** 发送频率 */
heartBeat.setRequestInterval(60);// 单位应该是秒
/** 设置心跳包请求后 等待反馈超时时间。 超过该时间后则调用KeepAliveRequestTimeoutHandler.CLOSE */
heartBeat.setRequestTimeout(15);// 单位应该是秒
connector.getSessionConfig().setKeepAlive(true);
connector.getFilterChain().addLast("heartbeat", heartBeat);
}
连接服务器:
private void Connect() {
while (!Closed) {
try {
ConnectFuture future = connector.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_POST));
future.awaitUninterruptibly();
session = future.getSession();
System.out.println("TCP 客户端启动");
break;
} catch (RuntimeIoException e) {
e.printStackTrace();
try {
this.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
关闭连接:
public void Close() {
Closed = true;
if (connector != null) {
connector.dispose(true);
connector = null;
}
}
发送数据:
public void Write(Object bs) {
if (session != null) {
session.write(bs);
}
}
3.一些说明
配置解码器与编码器
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new AppProtocolCodecFactory()));
为什么要配置这个,因为一般写出与读入时都是字节数组,而我们一般操作的是我们自己定义的对象,所以可以通过自定义这个ProtocolCodecFactory去进行转换。
public class AppProtocolCodecFactory implements ProtocolCodecFactory {
private String tag = "AppProtocolCodecFactory";
@Override
public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
//编码器,可以通过它将写入的对象转为写入的数组
return new AppProtocolEncoder();
}
@Override
public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
//解码器,通过它将读入的数组转为我们想看到的对象
return new AppProtocolDecoder();
}
public class AppProtocolEncoder extends ProtocolEncoderAdapter {
@Override
public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception {
//这个Object是发送数据时传入的那个Object,就是我们使用的对象
我们的对象 m = (我们的对象) o;
Logger.e(tag, "encode");
if (o == null) {
Logger.e(tag, "AppSocketMessage is null");
} else {
IoBuffer buffer = IoBuffer.allocate(20);
// 自动扩容
buffer.setAutoExpand(true);
// 自动收缩
buffer.setAutoShrink(true);
buffer.put(getSocketSendData(m));//把对象转为数组类型
buffer.flip();
protocolEncoderOutput.write(buffer);
}
}
}
public class AppProtocolDecoder extends ProtocolDecoderAdapter {
@Override
public void decode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput protocolDecoderOutput) throws Exception {
Logger.e(tag, "decode");
int limit = ioBuffer.limit();
Logger.e(tag,"decode num :"+limit);
byte[] bytes = new byte[limit];
ioBuffer.get(bytes);
我们的对象m = new 我们的对象();//把服务器数据读进来的是数组,要转为我们想看到的对象
if (limit >= AppSocketHead.HEAD_LENGTH) {
m.ResponseHeader = getHead(bytes);//返回的数组中读取信息头
m.ResponseBody = getResponseBody(bytes);//返回的数组中读取信息体
}
protocolDecoderOutput.write(m);
}
}
}
设置心跳
就算服务器不是使用mina框架,你也可以使用mina的心跳模块,前提是服务器支持心跳监听。
设置使用心跳代码在上面写过,如下:
//设置心跳工程
KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
当读操作空闲时发送心跳
KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory);
// 设置心跳包请求后超时无反馈情况下的处理机制,默认为关闭连接,在此处设置为输出日志提醒
heartBeat.setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler.LOG);
/** 是否回发 */
heartBeat.setForwardEvent(false);
/** 发送频率 */
heartBeat.setRequestInterval(5);// 单位应该是秒
/** 设置心跳包请求后 等待反馈超时时间。 超过该时间后则调用KeepAliveRequestTimeoutHandler.CLOSE */
heartBeat.setRequestTimeout(15);// 单位应该是秒
connector.getSessionConfig().setKeepAlive(true);
connector.getFilterChain().addLast("heartbeat", heartBeat);
KeepAliveMessageFactoryImpl是实现KeepAliveMessageFactory接口的类,该类有以下方法:
//
Object getRequest(IoSession session)
Object getResponse(IoSession session, Object request)
boolean isRequest(IoSession session, Object message)
boolean isResponse(IoSession session, Object message)
下面是我的实现类,不多说,看注释就懂了:
public class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {
private String tag = "KeepAliveMessageFactoryImpl";
private static final String ResponseStr = "keepalive_response";
private static final String RequestStr = "keepalive_request";
@Override
public Object getRequest(IoSession session) {
Logger.e(tag, "getRequest");
return getKeepAliveData();//返回心跳请求数据
}
private AppSocketMessage getKeepAliveData() {
//....你的服务器心跳需要的数据
return m;
}
@Override
public Object getResponse(IoSession session, Object request) {
Logger.e(tag, "getResponse");
return ResponseStr;//返回心跳请求返回数据,这里将数据进行处理封装成你想要的数据
}
//true if and only if the specified message is a keep-alive response message;
@Override
public boolean isRequest(IoSession session, Object message) {
Logger.e(tag, "isRequest");
AppSocketMessage sm = (AppSocketMessage) message;
if (sm != null && sm.SendBody != null && sm.SendBody.equals(RequestStr)) {
Logger.e(tag, "isRequest : 是请求心跳包");
return true;
}
return false;
}
//true if and only if the specified message is a keep-alive request message.
@Override
public boolean isResponse(IoSession session, Object message) {
Logger.e(tag, "isResponse");
AppSocketMessage sm = (AppSocketMessage) message;
if (sm != null && sm.ResponseBody != null && sm.ResponseBody.trim().equals(ResponseStr)) {
Logger.e(tag, "isResponse : 是返回心跳包");
return true;
}
return false;
}
}
转载注明:http://blog.csdn.net/u014614038/article/details/78564838