Mina简介
Apache MINA(Multipurpose Infrastructure 多功能框架 for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序,MINA 所支持的功能也在进一步的扩展中。
Apache官方网站:
http://mina.apache.org
Android用jar包等资源
http://pan.baidu.com/s/1i3sY1N3
配置jar包
准备
- 服务器端一共要用到四个jar包,包括一个日志包,它们分别为 mina-core-2.0.7.jar , slf4j-log4j12-1.7.6.jar , slf4j-api-1.7.6.jar , log4j-1.2.17.jar。将他们放在lib中,并加载进去。
- 如果要使用log4j.jar包,则要在项目的src目录下新建一个log4j.properties,内容详见附件。
- Android客户端要加入的jar包:mina-core-2.0.7.jar 和 slf4j-android-1.6.1-RC1.jar。Android自带Log,所以就不使用Mina的日志包了。
不知道你们注意到了没,客户端的代码与服务器端的极其相似,不同的是服务器是创建NioSocketAcceptor对象,而客户端是创建NioSocketConnect对象。当然同样需要添加编码解码过滤器和业务逻辑过滤器。
Mina的更多功能
- (1)拿到所有客户端Session
Collection<IoSession> sessions = session.getService().getManagedSessions().values(); - (2)自定义编码解码器,可以对消息进行预处理。要继承ProtocolEncoder和ProtocolDecode类。
- (3)数据对象的传递
服务器代码
public class Demo {
//日志类的实现
private static Logger logger = Logger.getLogger(Demo.class);
//端口号,要求客户端与服务器端一致
private static int PORT = 4445;
public static void main(String[] args) {
try {
//创建一个【非阻塞】的server端的Socket
IoAcceptor acceptor = new NioSocketAcceptor();
//为接收器设置管理服务
acceptor.setHandler(new MyIoHandlerAdapter());
//绑定端口
acceptor.bind(new InetSocketAddress(PORT));
// 设置过滤器(使用Mina提供的文本换行符编解码器)
acceptor.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
//设置读取数据的缓冲区大小
acceptor.getSessionConfig().setReadBufferSize(1024);
//读写通道10秒内无操作进入空闲状态
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
logger.info("服务器启动成功... 端口号为:" + PORT);
} catch (Exception e) {
logger.error("服务器启动异常...", e);
e.printStackTrace();
}
}
}
服务器Log
//相当于将服务器分成了七个状态,而每个状态都有自己的一套逻辑处理方案。也可 implements IoHandler
public class MyIoHandlerAdapter extends IoHandlerAdapter {
//日志类的实现
public static Logger logger = Logger.getLogger(MyIoHandlerAdapter.class);
//当一个Session 对象被创建的时候被调用。对于TCP 连接来说,连接被接受的时候调用,但要注意此时TCP 连接并未建立
//对于UDP 来说,当有数据包收到的时候回调这个方法,因为UDP 是无连接的。
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.info("服务器与客户端创建连接...session.getId()="+session.getId());
super.sessionCreated(session);
}
//在连接被打开时调用,它总是在sessionCreated()方法之后被调用。
//对于TCP 来 说,它是在连接被建立之后调用,你可以在这里执行一些认证操作、发送数据等。
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.info("服务器与客户端连接打开...");
super.sessionOpened(session);
}
//接收到消息时调用的方法,也就是用于接收消息的方法
//一般情况下,message 是一个IoBuffer 类,如果你使用了协议编解码器,那么可以强制转换为你需要的类型。
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String msg = message.toString();
//如果客户端发来exit,则关闭该连接
if ("exit".equals(msg)) session.close(true);
//向客户端发送消息
Date date = new Date();
session.write(date);
logger.info("服务器接受消息成功...message="+msg);
super.messageReceived(session, message);
}
//当发送消息成功时调用这个方法,注意这里的措辞"发送成功之后",也就是说发送消息是不能用这个方法的。
@Override
public void messageSent(IoSession session, Object message) throws Exception {
logger.info("服务器发送消息成功...message="+message.toString());
super.messageSent(session, message);
}
//***********************************************************************************************************
//这个方法在IoSession 的通道进入空闲状态时调用,对于UDP 协议来说,这个方法始终不会被调用。
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
logger.info("服务器进入空闲状态...status="+status);
super.sessionIdle(session, status);
}
//对于TCP 来说,连接被关闭时,调用这个方法。对于UDP 来说,IoSession 的close()方法被调用时才会回掉这个方法。
@Override
public void sessionClosed(IoSession session) throws Exception {
logger.info("服务器与客户端断开连接...");
super.sessionClosed(session);
}
//这个方法在你的程序、Mina 自身出现异常时回调,一般这里是关闭IoSession。
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
logger.info("服务器发送异常...");
super.exceptionCaught(session, cause);
}
}
客户端Activity
public class MainActivity extends Activity implements OnClickListener {
private EditText et;
private Button send;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.et);
send = (Button) findViewById(R.id.send);
send.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.send:
send();
break;
}
}
private void send() {
final String content = et.getText().toString().trim();
if (TextUtils.isEmpty(content)) {
Toast.makeText(this, "内容不能为空", Toast.LENGTH_SHORT).show();
return;
}
new MinaThread(content).start();
}
}
客户端连接
public class MinaThread extends Thread {
private static final String HOST = "192.168.31.165";
private static final int PORT = 4445;
private IoSession session;
private String content;
public MinaThread(String content) {
this.content = content;
}
@Override
public void run() {
Log.d("TEST", "客户端链接开始...");
IoConnector connector = new NioSocketConnector();
//设置链接超时时间
connector.setConnectTimeoutMillis(30000);
//添加过滤器
//connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
connector.setHandler(new MyIoHandlerAdapter());
ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));//创建链接
future.awaitUninterruptibly();// 等待连接创建完成
session = future.getSession();//获得session
session.write(content);
session.getCloseFuture().awaitUninterruptibly();//等待连接断开
Log.d("TEST", "客户端断开...");
connector.dispose();
super.run();
}
}
客户端日志
public class MyIoHandlerAdapter extends IoHandlerAdapter {
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String msg = message.toString();
Log.d("bqt", "messageReceived:" + msg);
super.messageReceived(session, message);
}
//******************************************************************************************
@Override
public void messageSent(IoSession session, Object message) throws Exception {
Log.d("bqt", "messageSent...");
super.messageSent(session, message);
}
@Override
public void sessionClosed(IoSession session) throws Exception {
Log.d("bqt", "sessionClosed...");
super.sessionClosed(session);
}
@Override
public void sessionCreated(IoSession session) throws Exception {
Log.d("bqt", "sessionCreated...");
super.sessionCreated(session);
}
@Override
public void sessionOpened(IoSession session) throws Exception {
Log.d("bqt", "sessionOpened...");
super.sessionOpened(session);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
Log.d("bqt", "sessionIdle...");
super.sessionIdle(session, status);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
Log.d("bqt", "exceptionCaught...");
super.exceptionCaught(session, cause);
}
}
附件列表