Android 中使用Socket来实现客户端和服务器端(使用MINA框架)

时间:2022-12-08 14:51:14

首先使用MINA框架要先下载框架所需的JAR包,这里给出我打包好的资源,需要的可以下载点击打开链接

言归正传,先来介绍服务器端(因为这个框架主要是用在服务器的,所以用在android设备上会比较耗资源,我用了这个测试工具,一般二十几台设备还是可以的)

1、创建一个非阻塞的Server端的Socket

IoAcceptor accept = new NioSocketAcceptor();

2、设置过滤器,这里可以使用MINA提供的文本换行符编解码器也可以用自定义的编解码器

(1)提供的

TextLineCodecFactory lineCode = new TextLineCodecFactory(Charset.forName("UTF-8"),LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue());

这里还可以设置编解码的最大行的长度lineCode.setDecoderMaxLineLength(1024);lineCode.setEncoderMaxLineLength(1024);

然后acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(lineCode));

(2)使用自定义的编解码器

这里先定义一个编解码的工厂类CharsetCodeFactory 实现ProtocolCodecFactory

public class CharsetCodecFactory implements ProtocolCodecFactory {

@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {//返回一个解码器
return new CharsetDecoder();
}

@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {//返回一个编码器
return new CharsetEncoder();
}
}
编写编码器类

public class CharsetEncoder implements ProtocolEncoder {
private static String TAG = "CharsetEncoder";
private final static Charset charset = Charset.forName("UTF-8");

@Override
public void dispose(IoSession session) throws Exception {
Log.d(TAG, "#############dispose############");
}

@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
Log.d(TAG, "#############字符编码############");
IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);//设置缓冲区,根据传输内容大小自动变更
buff.putString(message.toString(), charset.newEncoder());//设置字符编码
// put 当前系统默认换行符
buff.putString(LineDelimiter.DEFAULT.getValue(), charset.newEncoder());
// 为下一次读取数据做准备
buff.flip();
out.write(buff);
}
}
编写解码器类

public class CharsetDecoder implements ProtocolDecoder {

private static String TAG = "CharsetDecoder";

private final static Charset charset = Charset.forName("UTF-8");
// 可变的IoBuffer数据缓冲区
private IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);

@Override
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
Log.d(TAG,"#########decode#########");

// 如果有消息
while (in.hasRemaining()) {
// 判断消息是否是结束符,不同平台的结束符也不一样;
// windows换行符(\r\n)就认为是一个完整消息的结束符了; UNIX 是\n;MAC 是\r
byte b = in.get();
if (b == '\n') {
buff.flip();
byte[] bytes = new byte[buff.limit()];
buff.get(bytes);
String message = new String(bytes, charset);

buff = IoBuffer.allocate(100).setAutoExpand(true);

// 如果结束了,就写入转码后的数据
out.write(message);
Log.d(TAG,"message: " + message);
} else {
buff.put(b);
}
}
}

@Override
public void dispose(IoSession session) throws Exception {
Log.d(TAG,"#########dispose#########");
Log.d(TAG,"============"+session.getCurrentWriteMessage());
}

@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
Log.d(TAG,"#########完成解码#########");
}
}
3、设置读取数据的缓冲区大小

acceptor.getSessionConfig().setReadBufferSize(2048);

4、设置读写的通道如果10秒内无操作就进入空闲状态

acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,10);

5、为接收器设置管理服务(核心处理)

acceptor.setHandler(new MyServerHandler());

其中MyServerHandler为封装好的逻辑处理类

/**
*
* @author huangdianhua
* @date 2016年8月11日 下午1:03:51
*/
public class MyServerHandler extends IoHandlerAdapter {
private static String TAG = "MyServerHandler";

// 从端口接受消息,会响应此方法来对消息进行处理
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String msg = message.toString();
Log.d(TAG, "服务器接受消息成功..." + msg);
// 拿到所有的客户端Session
Collection<IoSession> sessions = session.getService().getManagedSessions().values();
// 向所有客户端发送数据
for (IoSession sess : sessions) {
sess.write(msg);
}
}

// 向客服端发送消息后会调用此方法
@Override
public void messageSent(IoSession session, Object message) throws Exception {
Log.d(TAG, "服务器发送消息成功...");
super.messageSent(session, message);
}

// 关闭与客户端的连接时会调用此方法
@Override
public void sessionClosed(IoSession session) throws Exception {
Log.d(TAG, "服务器与客户端断开连接...");
CloseFuture closeFuture = session.close(true);
closeFuture.addListener(new IoFutureListener<IoFuture>() {
public void operationComplete(IoFuture future) {
if (future instanceof CloseFuture) {
((CloseFuture) future).setClosed();
}
};
});
}

// 服务器与客户端创建连接
@Override
public void sessionCreated(IoSession session) throws Exception {
Log.d(TAG, "服务器与客户端创建连接...");

}

// 服务器与客户端连接打开
@Override
public void sessionOpened(IoSession session) throws Exception {
Log.d(TAG, "服务器与客户端连接打开...");
super.sessionOpened(session);
}

@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
Log.d(TAG, "服务器进入空闲状态...");
super.sessionIdle(session, status);
}

@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
Log.d(TAG, "服务器发送异常...");
super.exceptionCaught(session, cause);
}
}

6、绑定端口

acceptor.bind(new InetSocketAddress(PORT));

以上就是服务器端的具体实现方式

下面介绍客户端的具体实现过程

1、创建一个连接器

IoConnector connector = new NioSocketConnector();

2、设置超时时间

connector.setConnectTimeoutMillis(3000);

3、添加过滤器(这个和服务器端的设置一样)

4、为接收器设置管理服务(这个也是和服务器是一样设置的)

connector.setHandler(new MinaClientHandler());

/**
*
* @author huangdianhua
* @date 2016年8月11日 下午4:28:11
*/
public class MinaClientHandler extends IoHandlerAdapter {
private static String TAG = "MinaClientHandler";

@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
Log.d(TAG, "客户端发生异常" + cause.getMessage());
super.exceptionCaught(session, cause);
}

@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = message.toString();
Log.d(TAG, "客户端接收到的信息为:" + msg);

Intent intent = new Intent();
intent.setAction(CommonUtil.SEND_BROADCAST);
intent.putExtra("name", msg);
MyApplication.mContext.sendBroadcast(intent);
super.messageReceived(session, message);
}

@Override
public void messageSent(IoSession session, Object message) throws Exception {
// TODO Auto-generated method stub
super.messageSent(session, message);
}
}


5、为连接器创建连接

ConnectFuture future = connector.connect(new InetSocketAddress(IP,PORT));//创建链接

future.awaitUninterruptibly();//等待连接创建完成

6、获得创建连接得到的session

session = future.getSession();

session.write("start");//写入信息

以上就是客户端的具体实现过程

参考点击打开链接