第二篇帖子中 没有心跳 断线从连
我的第一次使用
Android客户端
MinaClient.java
package com.wjbzg.www.ernie_yaojiangji;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import com.google.gson.Gson;
import com.wjbzg.www.connect.CustomPack;
import com.wjbzg.www.connect.CustomProtocolCodecFactory;
import com.wjbzg.www.fragment.IoSessionGet;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import utils.Base64Utils;
public class Home3Activity extends AppCompatActivity {
private static final String MINA_HOST = "192.168.1.7";
private static final int MINA_PORT = 7777;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home3);
openSession();
}
private void openSession() {
new Thread(new Runnable() {
@Override
public void run() {
// 获取当前系统时间戳
long start = System.currentTimeMillis();
// 创建一个非阻塞的客户端
IoConnector connector = new NioSocketConnector();
// 设置编码过滤器
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CustomProtocolCodecFactory(Charset.forName("UTF-8"))));
// 设置缓冲区大小
connector.getSessionConfig().setReadBufferSize(1024);
// 设置空闲时间
connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 绑定逻辑处理Handler
connector.setHandler(new MyClientHandler());
// 创建连接
ConnectFuture future = connector.connect(new InetSocketAddress(MINA_HOST, MINA_PORT));
// 这里采用监听方式获取session
future.addListener(new IoFutureListener<IoFuture>() {
// 当连接创建完成
public void operationComplete(IoFuture future) {
IoSession session = future.getSession();
// sendData(session);
Log.e("Tag","----------------------------测试数据准备发送-----------------------------");
String content = "{'op':'init','m_id':'1'}";
String enToStr = Base64.encodeToString(content.getBytes(), Base64.NO_WRAP);
try {
Log.e("Tag","测试数据 加密后"+enToStr);
CustomPack pack = new CustomPack((byte) 1, enToStr);
session.write(pack);
//将ioSession 设置成单例的,方便其他地方获取
IoSessionGet ioSessionGet = new IoSessionGet();
ioSessionGet.setIo(session);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("Tag","----------------------------测试数据发送完毕-----------------------------");
}
});
}
}).start();
}
class MyClientHandler extends IoHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(MyClientHandler.class);
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
Gson gson = new Gson();
CustomPack pack = (CustomPack) message;
String content = pack.getContent();
//解密
String decodedString = Base64Utils.getFromBase64(content);
// String decodedString =new String(Base64.decode(content,Base64.DEFAULT));
// Log.e("Tag","客户端接收消息成功:" + decodedString);
JSONObject jsonObject = new JSONObject(decodedString);
String op = jsonObject.getString("op");
List goods = new ArrayList<>();
if (op.equals("good_list")){
//商品列表
// {"op":"good_list",
// "data":{"list":[{"good_id":1,"good_name":"森海耳机mx500"},{"good_id":2,"good_name":"兰蔻1x 口红"},{"good_id":3,"good_name":"zipoo打火机"},{"good_id":4,"good_name":"iphone xs 64G"},{"good_id":5,"good_name":"普通耳机"},{"good_id":6,"good_name":"纪念币"},{"good_id":7,"good_name":"鼠标wifi"},{"good_id":8,"good_name":"蓝牙耳机"},{"good_id":9,"good_name":"钢笔英雄"},{"good_id":10,"good_name":"漫步者mp3"},{"good_id":11,"good_name":"金士顿 U盘"}]},
// "state":"1",
// "message":"获取商品列表成功"}
Log.e("Tag","客户端接收消息成功,商品列表:" + decodedString);
Intent intent = new Intent();
intent.setAction("com.example.administrator.myapplication.MY_BROADCAST");
intent.putExtra("name", decodedString);
sendBroadcast(intent);
}else if (op.equals("init")){
//欢迎你
}else if (op.equals("good_state")){
//商品状态
//{"op":"good_state",
// "data":{"chanelList":[{"id":1,"m_id":1,"stock":5,"state":1,"position":1,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":2,"m_id":1,"stock":5,"state":1,"position":2,"good_id":1,"winning_rate":50,"good_name":"口红"},{"id":3,"m_id":1,"stock":5,"state":1,"position":3,"good_id":1,"winning_rate":50,"good_name":"钢笔"},{"id":4,"m_id":1,"stock":0,"state":1,"position":4,"good_id":1,"winning_rate":50,"good_name":"U盘"},{"id":5,"m_id":1,"stock":0,"state":1,"position":5,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":6,"m_id":1,"stock":0,"state":1,"position":6,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":7,"m_id":1,"stock":0,"state":1,"position":7,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":8,"m_id":1,"stock":0,"state":1,"position":8,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":9,"m_id":1,"stock":0,"state":1,"position":9,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":10,"m_id":1,"stock":0,"state":1,"position":10,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":11,"m_id":1,"stock":0,"state":1,"position":11,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":12,"m_id":1,"stock":0,"state":1,"position":12,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":13,"m_id":1,"stock":0,"state":1,"position":13,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":14,"m_id":1,"stock":0,"state":1,"position":14,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":15,"m_id":1,"stock":0,"state":1,"position":15,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":16,"m_id":1,"stock":0,"state":1,"position":16,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":17,"m_id":1,"stock":0,"state":1,"position":17,"good_id":1,"winning_rate":50,"good_name":"蓝牙耳机"},{"id":18,"m_id":1,"stock":5,"state":1,"position":18,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":19,"m_id":1,"stock":5,"state":1,"position":19,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":20,"m_id":1,"stock":5,"state":1,"position":20,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":21,"m_id":1,"stock":5,"state":1,"position":21,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":22,"m_id":1,"stock":5,"state":1,"position":22,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":23,"m_id":1,"stock":5,"state":1,"position":23,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":24,"m_id":1,"stock":5,"state":1,"position":24,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":25,"m_id":1,"stock":5,"state":1,"position":25,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":26,"m_id":1,"stock":5,"state":1,"position":26,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":27,"m_id":1,"stock":5,"state":1,"position":27,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":28,"m_id":1,"stock":5,"state":1,"position":29,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":29,"m_id":1,"stock":5,"state":1,"position":29,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":30,"m_id":1,"stock":5,"state":1,"position":30,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":31,"m_id":1,"stock":5,"state":1,"position":31,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":32,"m_id":1,"stock":5,"state":1,"position":32,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":33,"m_id":1,"stock":5,"state":1,"position":33,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":34,"m_id":1,"stock":5,"state":1,"position":34,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":35,"m_id":1,"stock":5,"state":1,"position":35,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":36,"m_id":1,"stock":5,"state":1,"position":36,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":37,"m_id":1,"stock":5,"state":1,"position":37,"good_id":1,"winning_rate":50,"good_name":"耳机"},{"id":38,"m_id":1,"stock":5,"state":1,"position":38,"good_id":1,"winning_rate":50,"goo
Log.e("Tag","客户端接收消息成功,商品状态:" + decodedString);
Intent intent = new Intent();
intent.setAction("com.example.administrator.myapplication.GoodsStateBROADCAST");
intent.putExtra("good_state",decodedString);
sendBroadcast(intent);
}else if (op.equals("open ")){
//抽奖
String state = jsonObject.getString("state");
if (state.equals("1")){
String postion = jsonObject.getString("postion");
int p = Integer.parseInt(postion);
String number_HEX = Integer.toHexString(p);
String data = "FA FE 01 "+number_HEX+" 01 CC DD DF";
// serialPortUtils.sendSerialPort3(data);
// openSendData(session,postion);
Log.e("Tag","----------------------------测试数据准备发送-----------------------------");
// 模拟发送100次数据
for (int i = 0; i < 1; i++) {
//String content = "nnnn:" + i;
String contents = "{'op':'init','postion':"+postion+",'state':'1','message':'转动成功','m_id':'1'}";
String enToStr = Base64.encodeToString(contents.getBytes(), Base64.NO_WRAP);
try {
Log.e("TAG",""+enToStr);
Log.e("Tag","测试数据 加密后"+enToStr);
CustomPack pack2 = new CustomPack((byte) i, enToStr);
session.write(pack2);
} catch (Exception e) {
e.printStackTrace();
}
}
Log.e("Tag","----------------------------测试数据发送完毕-----------------------------");
}
}
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
CustomPack pack = (CustomPack) message;
Log.e("Tag","客户端发送消息成功:" + pack);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
Log.e("Tag","客户端处理消息异常:" + cause.getMessage());
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
// 空闲时,关闭session
if (status == IdleStatus.BOTH_IDLE) {
Log.e("Tag","session进入空闲,准备关闭session");
//session.closeNow();
}
}
}
}
CustomPack.java
package com.fudai.mina.protocol2;
/*
自定义协议包
协议为– 数据长度(4个字节)+ 协议编号(1字节)+ 真实数据。
*/
public class CustomPack {
/**
* 0x00表示请求
*/
public static final byte REQUEST = 0x00;
/**
* 0x01表示回复
*/
public static final byte RESPONSE = 0x01;
// 总长度(编号字节 + 长度的字节 + 包体长度字节)
private int len;
// 版本号
private byte flag;
// 发送人,只是服务端-客户端,暂时无需发送人 接收人
// private long sender;
// 接收人
// private long receiver;
// 包体
private String content;
// 构造方法设置协议
public CustomPack(byte flag, String content) {
this.flag = flag;
this.content = content;
// 版本类型的长度1个字节, len的长度4个字节, 内容的字节数
this.len = 1 + 4 + (content == null ? 0 : content.getBytes().length);
}
public int getLen() {
return len;
}
public void setLen(int len) {
this.len = len;
}
public byte getFlag() {
return flag;
}
public void setFlag(byte flag) {
this.flag = flag;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "CustomPack{" +
"len=" + len +
", flag=" + flag +
", content='" + content + '\'' +
'}';
}
}
这是我第一次使用的, 后来经过查阅资料,才明白要把 mina代码写在服务Service中
CustomProtocolCodecFactory.java
package com.wjbzg.www.connect;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import java.nio.charset.Charset;
/*
自定义编解码工厂类
*/
public class CustomProtocolCodecFactory implements ProtocolCodecFactory {
private final ProtocolEncoder encoder;
private final ProtocolDecoder decoder;
public CustomProtocolCodecFactory() {
this(Charset.forName("UTF-8"));
}
// 构造方法注入编解码器
public CustomProtocolCodecFactory(Charset charset) {
this.encoder = new CustomProtocolEncoder(charset);
this.decoder = new CustomProtocolDecoder(charset);
}
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}
}
CustomProtocolDecoder.java
package com.wjbzg.www.connect;
import android.util.Base64;
import android.util.Log;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import java.nio.charset.Charset;
/*
*
* describe 自定义解码器
* @author xmc
* @param * @param null
* @return
*/
public class CustomProtocolDecoder extends CumulativeProtocolDecoder {
private final Charset charset;
public CustomProtocolDecoder() {
this.charset = Charset.defaultCharset();
}
// 构造方法注入编码格式
public CustomProtocolDecoder(Charset charset) {
this.charset = charset;
}
@Override
protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
// 包头的长度
final int PACK_HEAD_LEN = 5;
// 拆包时,如果可读数据的长度小于包头的长度,就不进行读取
if (in.remaining() < PACK_HEAD_LEN) {
System.out.println("可读数据的长度小于包头的长度");
Log.e("Tag","可读数据的长度小于包头的长度");
return false;
}
if (in.remaining() > 1) {
// 标记设为当前
in.mark();
// 获取总长度
int length = in.getInt(in.position());
// 如果可读取数据的长度 小于 总长度 - 包头的长度 ,则结束拆包,等待下一次
if (in.remaining() < (length - PACK_HEAD_LEN)) {
System.out.println("可读取数据的长度 小于 总长度"+length);
Log.e("Tag","可读取数据的长度 小于 总长度"+length);
in.reset();
return false;
} else {
System.out.println("读取一条完整记录");
Log.e("Tag","读取一条完整记录");
// 重置,并读取一条完整记录
in.reset();
byte[] bytes = new byte[length];
// 获取长度4个字节、版本1个字节、内容
in.get(bytes, 0, length);
byte flag = bytes[4];
String content = new String(bytes, PACK_HEAD_LEN, length - PACK_HEAD_LEN, charset);
//64解码
// String contentBase64 = new String(Base64.encode(content.getBytes("utf-8"), Base64.NO_WRAP),"utf-8");
// 封装为自定义的java对象
CustomPack pack = new CustomPack(flag,content);
out.write(pack);
//测试读取json 对象转Map
/*JSONObject jsonObject = JSONObject.parseObject(pack.getContent());
Map<String,Object> map = jsonObject;
System.out.println("map对象是:" + map);
Object object = map.get("message");
System.out.println("message的值是:"+object);*/
// 如果读取一条记录后,还存在数据(粘包),则再次进行调用
return in.remaining() > 0;
}
}
return false;
}
}
CustomProtocolEncoder.java
package com.wjbzg.www.connect;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import java.nio.charset.Charset;
/*
*
* describe 自定义编码器
* @author xmc
* @param * @param null
* @return
*/
public class CustomProtocolEncoder implements ProtocolEncoder {
private final Charset charset;
public CustomProtocolEncoder() {
this.charset = Charset.defaultCharset();
}
// 构造方法注入编码格式
public CustomProtocolEncoder(Charset charset) {
this.charset = charset;
}
@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
// 转为自定义协议包
CustomPack customPack = (CustomPack) message;
// 初始化缓冲区
IoBuffer buffer = IoBuffer.allocate(customPack.getLen())
.setAutoExpand(true);
// 设置长度、报头、内容
buffer.putInt(customPack.getLen());
buffer.put(customPack.getFlag());
if (customPack.getContent() != null) {
buffer.put(customPack.getContent().getBytes());
}
// 重置mask,发送buffer
buffer.flip();
out.write(buffer);
}
@Override
public void dispose(IoSession session) throws Exception {
}
}
本文介绍了一个基于Android的Mina客户端实现案例,详细展示了如何使用Mina框架进行网络通信,包括连接配置、消息收发、心跳检测及异常处理等核心功能。
404

被折叠的 条评论
为什么被折叠?



