MINA 实现聊天功能

简介:

在《MINA 快速入门》一文中,我们介绍了如何利用 MINA 快速构建一个 Time Server(时间服务器)。在《Netty 实现聊天功能》一文,我们也介绍了如何用 Netty 实现聊天功能。由于 MINA 和 Netty 是同一个作者,架构类似,如果你掌握其中一个,学习另外一个也不是难事。现在我们就用 MINA 来实现聊天功能。

准备

  • JDK 7+
  • Maven 3.2.x
  • MINA 2.x
  • Eclipse 4.x

服务端

让我们从 handler (处理器)的实现开始,handler 是由 MINA 生成用来处理 I/O 事件的, 处理器继承自 IoHandlerAdapter。

SimpleChatServerHandler.java

public class SimpleChatServerHandler extends IoHandlerAdapter { // (1) private final Set<IoSession> sessions = Collections
 .synchronizedSet(new HashSet<IoSession>()); // (2) @Override public void sessionCreated(IoSession session) throws Exception {// (3)
 sessions.add(session);
 broadcast(" has join the chat", session);
 }

 @Override public void sessionClosed(IoSession session) throws Exception {// (4)
 sessions.remove(session);
 broadcast(" has left the chat", session);
 }

 @Override public void messageReceived(IoSession session, Object message) throws Exception {// (5)
 String str = message.toString();
 broadcast(str, session);
 }

 @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception {// (6)
 System.out.println("[Server] IDLE " + session.getRemoteAddress()
 + session.getIdleCount(status));
 }

 @Override public void exceptionCaught(IoSession session, Throwable cause) {
 cause.printStackTrace();// (7)
 System.out.println("[Server] Client:" + session.getRemoteAddress()
 + "异常");
 // 遇到未捕获的异常,则关闭连接
 session.close(true);
 }

 /**
 * 广播消息
 * 
 * @param message
 */ private void broadcast(String message, IoSession exceptSession) {// (8) synchronized (sessions) {
 for (IoSession session : sessions) {
 if (session.isConnected()) {
 if (session.equals(exceptSession)) {
 session.write("[You]" + message);
 } else {
 session.write("[Client" + session.getRemoteAddress()
 + "] " + message);
 }

 }
 }
 }
 }
}

1.SimpleChatServerHandler 继承自 IoHandlerAdapter,这个类实现了 IoHandler 接口,IoHandlerAdapter 提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承 IoHandlerAdapter 类而不是你自己去实现接口方法。

2.Set<IoSession> sessions 用来存储所有的 连接上来的 session.

3.覆盖了 sessionCreated() 事件处理方法。每当从服务端收到新的客户端连接时,客户端的 IoSession 就存入存入 sessions 列表中,并通知列表中的其他客户端 IoSession

4.覆盖了 sessionClosed() 事件处理方法。每当从服务端收到客户端断开时,客户端的 IoSession 从 sessions 列表中,并通知列表中的其他客户端 IoSession

5.覆盖了 messageReceived() 事件处理方法。每当从服务端读到客户端写入信息时,将信息广播给其他客户端的 IoSession。

6.覆盖了 sessionIdle() 事件处理方法。服务端监听到客户端闲置情况

7.exceptionCaught() 事件处理方法是当出现 Throwable 对象才会被调用,即当 MINA 由于 IO 错误或者处理器在处理事件时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的 IoSession 给关闭掉。然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。

8.broadcast() 服务器用于广播的方法

SimpleChatServer.java

编写一个 main() 方法来启动服务端。

public class SimpleChatServer {

 public static void main(String[] args) {
 int port;
 if (args.length > 0) {
 port = Integer.parseInt(args[0]);
 } else {
 port = 8080;
 }

 SocketAcceptor acceptor = new NioSocketAcceptor(); // (1)

 acceptor.getFilterChain().addLast( "codec", 
 new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); // (2)
 acceptor.setHandler(new SimpleChatServerHandler()); // (3)

 acceptor.getSessionConfig().setReadBufferSize(2048); // (4)
 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 100);// (5) try {
 acceptor.bind(new InetSocketAddress(port)); // (6)
 } catch (IOException e) {
 e.printStackTrace();
 }
 System.out.println("[Server]Listening on port " + port);
 }
}

1.NioSocketAcceptor 基于 TCP/IP 的 socket 连接。

2.ProtocolCodecFilter 是编码和解码的过滤器链,将一个连入的 ByteBuffer 转化为消息 POJO,反之亦然。而TextLineCodecFactory是 MINA 提供的一个编解码是,可以方便处理基于文本的协议。

3.设置在处理器为之前创建的 SimpleChatServerHandler。

4.会话配置,设置字节缓存大小。

5.会话配置,设置闲置时间。

6.剩下的就是绑定端口然后启动服务。这里我们在机器上默认绑定了机器所有网卡上的 8080 端口。

恭喜!你已经完成了基于 MINA 聊天服务端程序。

客户端

SimpleChatClientHandler.java

客户端的处理类比较简单,只需要将读到的信息打印出来即可

public class SimpleChatClientHandler extends IoHandlerAdapter {
 @Override public void messageReceived(IoSession session, Object message) {
 String str = message.toString();
 System.out.println(str);
 }
}

SimpleChatClient.java

编写一个 main() 方法来启动客户端。

public class SimpleChatClient {
 private static final long CONNECT_TIMEOUT = 30 * 1000L; // 30 秒; private static final String HOSTNAME = "127.0.0.1";
 private static final int PORT = 8080;
 /**
 * @param args
 */ public static void main(String[] args) {

 NioSocketConnector connector = new NioSocketConnector(); // (1)
 connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
 connector.getFilterChain().addLast( "codec", 
 new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
 connector.setHandler(new SimpleChatClientHandler());
 IoSession session;
 ConnectFuture future = connector.connect(new InetSocketAddress(
 HOSTNAME, PORT)); // (2)
 future.awaitUninterruptibly();
 session = future.getSession();

 while(true){
 try {
 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 session.write(in.readLine());
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
}

1.NioSocketConnector 用于 TCP/IP 连接

2.连接到指定的服务器

运行效果

先运行 SimpleChatServer,再可以运行多个 SimpleChatClient,控制台输入文本继续测试

源码

https://github.com/waylau/apache-mina-2-user-guide-demossimplechat

参考

目录
相关文章
|
小程序 前端开发 iOS开发
微信小程序:多行文本溢出出现多余的文字-webkit-line-clamp
微信小程序:多行文本溢出出现多余的文字-webkit-line-clamp
670 0
微信小程序:多行文本溢出出现多余的文字-webkit-line-clamp
|
11月前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
381 2
|
NoSQL 关系型数据库 MySQL
一文吃透企业级elk技术栈:6. filebeat安装配置
一文吃透企业级elk技术栈:6. filebeat安装配置
|
存储 缓存 Java
释放C盘空间:释放Windows休眠文件和关闭虚拟内存
在 Windows 11 专业版中,可以通过以下步骤来释放休眠文件(Hibernate File),以释放磁盘空间。休眠文件是系统休眠(Hibernate)功能所需要的文件,它保存了系统的当前状态,以便在休眠状态下恢复。如果你不使用休眠功能,如果因为C盘空间不足,可以考虑释放这个文件来腾出磁盘空间。
25959 1
|
NoSQL Redis Docker
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
1480 0
|
Java Linux Maven
Maven 环境配置
**Maven配置摘要:** 确保安装JDK 1.7+ for Maven 3.3+. Maven自身占用约10MB,但本地仓库可能需500MB+空间。检查Java版本: - Windows: `java -version` in cmd - Linux/Mac: `java -version` in terminal. 支持所有操作系统。
|
前端开发 NoSQL Java
基于Springboot+Vue实现前后端分离商城管理系统
基于Springboot+Vue实现前后端分离商城管理系统
714 1
|
Python Perl
情人节到了,写一份爱心程序(python)
情人节到了,写一份爱心程序(python)
259 0
|
数据库
达梦(DM)5、6001网络通信异常
在连接数据库实例的时候,出现了如下异常信息,登录服务器失败,提示:错误号:6001 错误信息:网络通信异常
3526 0
达梦(DM)5、6001网络通信异常
|
JavaScript
美食杰项目 -- 菜品信息(五)
美食杰项目 -- 菜品信息(五)
美食杰项目 -- 菜品信息(五)