首页 > 其他分享 >Apache MiNa 实现多人聊天室

Apache MiNa 实现多人聊天室

时间:2023-01-10 15:36:29浏览次数:50  
标签:hoo 聊天室 01 MiNa mina Apache message com 2012


开发环境:

System:Windows

JavaSDK:1.6

IDE:eclipse、MyEclipse 6.6

开发依赖库:

Jdk1.4+、mina-core-2.0.4.jar、slf4j-api-1.5.11.jar、slf4j-log4j12-1.5.11.jar

​http://hoojo.blogjava.net​

前不久用Socket写的聊天程序,主要是手机端程序通过Socket连接服务器端的ServerSocket,然后服务器端根据客户端发送过来统一规范的报文。进行解析再用smack框架转发到openfire服务器,最后由openfire服务器向客户端程序发送聊天信息。

最近发现socket服务器资源消耗比较大。我是采用阻塞式多线程通信方式,这种方式会造成大量的服务器资源浪费、长期的占用服务器的CUP调度权,并且会长时间阻塞程序,等待客户端连接、发送消息等。

为了解决上面的状况,Apache MiNa能很好的解决这个问题。Mina采用的是非阻塞式、单线程、NIO通信方式。

非阻塞式通信的思想是:让一个线程同时完成多件事,这个线程会利用完成这件事的空余时间去完成另一件事,一刻也不闲着。这个线程同时也会不断监控每件事情中需要处理时间的发生,发生一个就处理一件,然后继续监听各自事情。

一、介绍

首先,Mina是个什么东西?看下官方网站(http://mina.apache.org/)对它的解释:

Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。

Apache Mina也称为:

 NIO框架

 网络套接字(networking socket)类库

 事件驱动的异步API(注意:在JDK7中也新增了异步API)

总之:我们简单理解它是一个封装底层IO操作,提供高级操作API的通讯框架!

二、服务器端编码工作

第一步:

使用Apache MiNa框架,你需要下载jar

下载地址:​​http://mina.apache.org/dyn/closer.cgi/mina/2.0.4/apache-mina-2.0.4-bin.zip​

你需要添加jar如下

Apache MiNa 实现多人聊天室_java

如果你使用日志,需要添加日志配置文件log4j.properties

第二步:

编写通信要用的解码工厂和编码器、解码器类,代码如下

package com.hoo.mina.code.factory; <!--CRLF--> 


<!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolCodecFactory; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolDecoder; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolEncoder; <!--CRLF-->
import com.hoo.mina.code.CharsetDecoder; <!--CRLF-->
import com.hoo.mina.code.CharsetEncoder; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 字符编码、解码工厂类,编码过滤工厂 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-26 下午01:08:50 <!--CRLF-->
* @file CharsetCodecFactory.java <!--CRLF-->
* @package com.hoo.mina.code.factory <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class CharsetCodecFactory implements ProtocolCodecFactory { <!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public ProtocolDecoder getDecoder(IoSession session) throws Exception { <!--CRLF-->
return new CharsetDecoder(); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public ProtocolEncoder getEncoder(IoSession session) throws Exception { <!--CRLF-->
return new CharsetEncoder(); <!--CRLF-->

}
<!--CRLF-->

}

解码类

package com.hoo.mina.code; <!--CRLF--> 


<!--CRLF-->
import java.nio.charset.Charset; <!--CRLF-->
import org.apache.log4j.Logger; <!--CRLF-->
import org.apache.mina.core.buffer.IoBuffer; <!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolDecoder; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolDecoderOutput; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 字符解码 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-26 上午11:14:18 <!--CRLF-->
* @file CharsetDecoder.java <!--CRLF-->
* @package com.hoo.mina.code <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class CharsetDecoder implements ProtocolDecoder { <!--CRLF-->


<!--CRLF-->
private final static Logger log = Logger.getLogger(CharsetDecoder.class); <!--CRLF-->


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


<!--CRLF-->

@Override
<!--CRLF-->
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { <!--CRLF-->
log.info("#########decode#########"); <!--CRLF-->


<!--CRLF-->
// 如果有消息 <!--CRLF-->
while (in.hasRemaining()) { <!--CRLF-->
// 判断消息是否是结束符,不同平台的结束符也不一样; <!--CRLF-->
// windows换行符(\r\n)就认为是一个完整消息的结束符了; UNIX 是\n;MAC 是\r <!--CRLF-->
byte b = in.get(); <!--CRLF-->
if (b == '\n') { <!--CRLF-->

buff.flip();
<!--CRLF-->
byte[] bytes = new byte[buff.limit()]; <!--CRLF-->

buff.get(bytes);
<!--CRLF-->
String message = new String(bytes, charset); <!--CRLF-->


<!--CRLF-->

buff = IoBuffer.allocate(100).setAutoExpand(true);
<!--CRLF-->


<!--CRLF-->
// 如果结束了,就写入转码后的数据 <!--CRLF-->

out.write(message);
<!--CRLF-->
//log.info("message: " + message); <!--CRLF-->
} else { <!--CRLF-->

buff.put(b);
<!--CRLF-->

}
<!--CRLF-->

}
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void dispose(IoSession session) throws Exception { <!--CRLF-->
log.info("#########dispose#########"); <!--CRLF-->

log.info(session.getCurrentWriteMessage());
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { <!--CRLF-->
log.info("#########完成解码#########"); <!--CRLF-->

}
<!--CRLF-->

}

上面的decode方法是解码方法,它主要是把读取到数据中的换行符去掉。因为在mina通信协议中以换行符为结束符,如果不定义结束符那么程序会在那里一直等待下一条发送的数据。

这里用到了IoBuffer,MiNa中传输的所有二进制信息都存放在IoBuffer中,IoBuffer是对Java NIO中ByteBuffer的封装(Mina2.0以前版本这个接口也是ByteBuffer),提供了更多操作二进制数据,对象的方法,并且存储空间可以自增长,用起来非常方便;简单理解,它就是个可变长度的byte字节数组!

1. static IoBuffer allocate(int capacity,boolean useDirectBuffer)

创建IoBuffer实例,第一个参数指定初始化容量,第二个参数指定使用直接缓冲区还是JAVA 内存堆的缓存区,默认为false。

2.IoBuffer setAutoExpand(boolean autoExpand)

这个方法设置IoBuffer 为自动扩展容量,也就是前面所说的长度可变,那么可以看出长度可变这个特性默认是不开启的。

3. IoBuffer flip()

limit=position, position=0,重置mask,为了读取做好准备,一般是结束buffer操作,将buffer写入输出流时调用;这个必须要调用,否则极有可能position!=limit,导致position后面没有数据;每次写入数据到输出流时,必须确保position=limit。

4. IoBuffer clear()与IoBuffer reset()

clear:limit=capacity , position=0,重置mark;它是不清空数据,但从头开始存放数据做准备---相当于覆盖老数据。

reset就是清空数据

5. int remaining()与boolean hasRemaining()

这两个方法一般是在调用了flip方法后使用的,remaining()是返回limt-position的值!hasRemaining()则是判断当前是否有数据,返回position < limit的boolean值!

编码类

package com.hoo.mina.code; <!--CRLF--> 


<!--CRLF-->
import java.nio.charset.Charset; <!--CRLF-->
import org.apache.log4j.Logger; <!--CRLF-->
import org.apache.mina.core.buffer.IoBuffer; <!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolEncoder; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolEncoderOutput; <!--CRLF-->
import org.apache.mina.filter.codec.textline.LineDelimiter; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 字符编码 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-26 上午11:32:05 <!--CRLF-->
* @file CharsetEncoder.java <!--CRLF-->
* @package com.hoo.mina.code <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class CharsetEncoder implements ProtocolEncoder { <!--CRLF-->
private final static Logger log = Logger.getLogger(CharsetEncoder.class); <!--CRLF-->
private final static Charset charset = Charset.forName("UTF-8"); <!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void dispose(IoSession session) throws Exception { <!--CRLF-->
log.info("#############dispose############"); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { <!--CRLF-->
log.info("#############字符编码############"); <!--CRLF-->

IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);
<!--CRLF-->

buff.putString(message.toString(), charset.newEncoder());
<!--CRLF-->
// put 当前系统默认换行符 <!--CRLF-->

buff.putString(LineDelimiter.DEFAULT.getValue(), charset.newEncoder());
<!--CRLF-->
// 为下一次读取数据做准备 <!--CRLF-->

buff.flip();
<!--CRLF-->


<!--CRLF-->

out.write(buff);
<!--CRLF-->

}
<!--CRLF-->

}

第三步:

编写IoHandler实现类代码,IoHander这里是Io读写的事件驱动类,这里的Io操作都会触发里面的事件。你所有的业务逻辑都应当在这个类中完成。

package com.hoo.mina.server.message; <!--CRLF--> 


<!--CRLF-->
import java.text.SimpleDateFormat; <!--CRLF-->
import java.util.Collection; <!--CRLF-->
import java.util.Date; <!--CRLF-->
import org.apache.mina.core.future.CloseFuture; <!--CRLF-->
import org.apache.mina.core.future.IoFuture; <!--CRLF-->
import org.apache.mina.core.future.IoFutureListener; <!--CRLF-->
import org.apache.mina.core.service.IoHandler; <!--CRLF-->
import org.apache.mina.core.session.IdleStatus; <!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.slf4j.Logger; <!--CRLF-->
import org.slf4j.LoggerFactory; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 处理服务器端消息 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-26 下午01:12:34 <!--CRLF-->
* @file ServerMessageHandler.java <!--CRLF-->
* @package com.hoo.mina.server.message <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class ServerMessageHandler implements IoHandler { <!--CRLF-->


<!--CRLF-->
private final static Logger log = LoggerFactory.getLogger(ServerMessageHandler.class); <!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void exceptionCaught(IoSession session, Throwable cause) throws Exception { <!--CRLF-->
log.info("服务器发生异常: {}", cause.getMessage()); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void messageReceived(IoSession session, Object message) throws Exception { <!--CRLF-->
log.info("服务器接收到数据: {}", message); <!--CRLF-->

String content = message.toString();
<!--CRLF-->
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); <!--CRLF-->
String datetime = sdf.format(new Date()); <!--CRLF-->


<!--CRLF-->
log.info("转发 messageReceived: " + datetime + "\t" + content); <!--CRLF-->


<!--CRLF-->
// 拿到所有的客户端Session <!--CRLF-->

Collection<IoSession> sessions = session.getService().getManagedSessions().values();
<!--CRLF-->
// 向所有客户端发送数据 <!--CRLF-->
for (IoSession sess : sessions) { <!--CRLF-->
sess.write(datetime + "\t" + content); <!--CRLF-->

}
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void messageSent(IoSession session, Object message) throws Exception { <!--CRLF-->
log.info("服务器发送消息: {}", message); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void sessionClosed(IoSession session) throws Exception { <!--CRLF-->
log.info("关闭当前session:{}#{}", session.getId(), session.getRemoteAddress()); <!--CRLF-->


<!--CRLF-->

CloseFuture closeFuture = session.close(true);
<!--CRLF-->
closeFuture.addListener(new IoFutureListener<IoFuture>() { <!--CRLF-->
public void operationComplete(IoFuture future) { <!--CRLF-->
if (future instanceof CloseFuture) { <!--CRLF-->

((CloseFuture) future).setClosed();
<!--CRLF-->
log.info("sessionClosed CloseFuture setClosed-->{},", future.getSession().getId()); <!--CRLF-->

}
<!--CRLF-->

}
<!--CRLF-->

});
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void sessionCreated(IoSession session) throws Exception { <!--CRLF-->
log.info("创建一个新连接:{}", session.getRemoteAddress()); <!--CRLF-->
session.write("welcome to the chat room !"); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void sessionIdle(IoSession session, IdleStatus status) throws Exception { <!--CRLF-->
log.info("当前连接{}处于空闲状态:{}", session.getRemoteAddress(), status); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void sessionOpened(IoSession session) throws Exception { <!--CRLF-->
log.info("打开一个session:{}#{}", session.getId(), session.getBothIdleCount()); <!--CRLF-->

}
<!--CRLF-->

}

sessionCreated:当一个新的连接建立时,由I/O processor thread调用;

sessionOpened:当连接打开是调用;

messageReceived: 当接收了一个消息时调用;

messageSent:当一个消息被(IoSession#write)发送出去后调用;

sessionIdle:当连接进入空闲状态时调用;

sessionClosed:当连接关闭时调用;

exceptionCaught:实现IoHandler的类抛出异常时调用;

一般情况下,我们最关心的只有messageReceived方法,接收消息并处理,然后调用IoSession的write方法发送出消息!(注意:这里接收到的消息都是Java对象,在IoFilter中所有二进制数据都被解码)一般情况下很少有人实现IoHandler接口,而是继承它的一个实现类IoHandlerAdapter,这样不用覆盖它的7个方法,只需要根据具体需求覆盖其中的几个方法就可以!

Iohandler的7个方法其实是根据session的4个状态值间变化来调用的:

 Connected:会话被创建并使用;

 Idle:会话在一段时间(可配置)内没有任何请求到达,进入空闲状态;

 Closing:会话将被关闭(剩余message将被强制flush);

 Closed:会话被关闭;

状态转换图如下:

Apache MiNa 实现多人聊天室_mina_02

第四步:

编写server启动类,bind端口、设置编码过程和核心业务处理器

package com.hoo.mina.server; <!--CRLF--> 


<!--CRLF-->
import java.io.IOException; <!--CRLF-->
import java.net.InetSocketAddress; <!--CRLF-->
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; <!--CRLF-->
import org.apache.mina.core.session.IdleStatus; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolCodecFilter; <!--CRLF-->
import org.apache.mina.transport.socket.SocketAcceptor; <!--CRLF-->
import org.apache.mina.transport.socket.nio.NioSocketAcceptor; <!--CRLF-->
import com.hoo.mina.code.factory.CharsetCodecFactory; <!--CRLF-->
import com.hoo.mina.server.message.ServerMessageHandler; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 服务器启动类 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-29 下午07:11:00 <!--CRLF-->
* @file MinaServer.java <!--CRLF-->
* @package com.hoo.mina.server <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class MinaServer { <!--CRLF-->


<!--CRLF-->
private SocketAcceptor acceptor; <!--CRLF-->


<!--CRLF-->
public MinaServer() { <!--CRLF-->
// 创建非阻塞的server端的Socket连接 <!--CRLF-->
acceptor = new NioSocketAcceptor(); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public boolean start() { <!--CRLF-->

DefaultIoFilterChainBuilder filterChain = acceptor.getFilterChain();
<!--CRLF-->
// 添加编码过滤器 处理乱码、编码问题 <!--CRLF-->
filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory())); <!--CRLF-->


<!--CRLF-->
/*LoggingFilter loggingFilter = new LoggingFilter(); <!--CRLF-->
loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO); <!--CRLF-->
loggingFilter.setMessageSentLogLevel(LogLevel.INFO); <!--CRLF-->
// 添加日志过滤器 <!--CRLF-->
filterChain.addLast("loger", loggingFilter);*/ <!--CRLF-->


<!--CRLF-->
// 设置核心消息业务处理器 <!--CRLF-->
acceptor.setHandler(new ServerMessageHandler()); <!--CRLF-->
// 设置session配置,30秒内无操作进入空闲状态 <!--CRLF-->

acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
<!--CRLF-->


<!--CRLF-->
try { <!--CRLF-->
// 绑定端口3456 <!--CRLF-->
acceptor.bind(new InetSocketAddress(3456)); <!--CRLF-->
} catch (IOException e) { <!--CRLF-->

e.printStackTrace();
<!--CRLF-->
return false; <!--CRLF-->

}
<!--CRLF-->
return true; <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public static void main(String[] args) { <!--CRLF-->
MinaServer server = new MinaServer(); <!--CRLF-->

server.start();
<!--CRLF-->

}
<!--CRLF-->

}

上面的代码主要完成启动参数的设置,如端口、session参数;消息核心业务处理器,这个比较关键,我们所有的业务都要在这里完成;然后就是日志、编码过滤器,我们可以对发送或接收到的消息进行处理、编码操作,在网络中传递数据都是字节流传递的,我们要获取消息必须把二进制的字节流转换的字符串来处理,所以这个也是必须的;同时你还可以对服务器添加日志过滤器,来显示日志。

这样服务器端程序就已经完成,你可以用socket或mina client等方式连接服务器,进行通信。

启动服务器,在浏览器中输入​​http://localhost:3456​​ 这里的服务器绑定的端口是3456

然后你在控制台中可以看到当前浏览器的一些基本信息,如果你看到这些信息就表示你服务器代码编写没有什么问题,应该可以成功建立客户端连接。信息如下:

2012-08-01 09:55:56,046 INFO [com.hoo.mina.server.message.ServerMessageHandler:75-NioProcessor-1] - 创建一个新连接:/127.0.0.1:2542
<!--CRLF-->

2012-08-01 09:55:56,046 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:86-NioProcessor-1] - 打开一个session:3#0
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-1] - 服务器发送消息: welcome to the chat room !
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-1] - #########decode#########
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: GET / HTTP/1.1
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-1] - 转发 messageReceived: 2012-08-01 09:55:56 GET / HTTP/1.1
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: Host: localhost:3456
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-1] - 转发 messageReceived: 2012-08-01 09:55:56 Host: localhost:3456
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-1] - 转发 messageReceived: 2012-08-01 09:55:56 User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1
<!--CRLF-->

2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
<!--CRLF-->
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 <!--CRLF-->
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-1] - 转发 messageReceived: 2012-08-01 09:55:56 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 <!--CRLF-->

其他内容省略……




三、客户端编码工作

第一步:

编写客户端消息核心处理业务类型,消息处理器

package com.hoo.mina.client.message; <!--CRLF--> 


<!--CRLF-->
import org.apache.mina.core.service.IoHandlerAdapter; <!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.slf4j.Logger; <!--CRLF-->
import org.slf4j.LoggerFactory; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> 客户端消息处理类 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-29 下午07:24:22 <!--CRLF-->
* @file ClientMessageHandlerAdapter.java <!--CRLF-->
* @package com.hoo.mina.client.message <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class ClientMessageHandlerAdapter extends IoHandlerAdapter { <!--CRLF-->


<!--CRLF-->
private final static Logger log = LoggerFactory.getLogger(ClientMessageHandlerAdapter.class); <!--CRLF-->


<!--CRLF-->
public void messageReceived(IoSession session, Object message) throws Exception { <!--CRLF-->

String content = message.toString();
<!--CRLF-->
log.info("client receive a message is : " + content); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public void messageSent(IoSession session , Object message) throws Exception{ <!--CRLF-->
log.info("messageSent 客户端发送消息:" + message); <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->

@Override
<!--CRLF-->
public void exceptionCaught(IoSession session, Throwable cause) throws Exception { <!--CRLF-->
log.info("服务器发生异常: {}", cause.getMessage()); <!--CRLF-->

}
<!--CRLF-->

}

这里我们没有实现IoHandler这个接口,而是继承了IoHandlerAdapter这类,覆盖了messageReceived、messageSent这两个方法。IoHandlerAdapter是IoHandler接口的一个实现,我们这里没有必要实现IoHandler的所有方法。

第二步:

编写连接服务器的代码,设置核心消息处理器

package com.hoo.mina.client; <!--CRLF--> 


<!--CRLF-->
import java.net.InetSocketAddress; <!--CRLF-->
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; <!--CRLF-->
import org.apache.mina.core.future.CloseFuture; <!--CRLF-->
import org.apache.mina.core.future.ConnectFuture; <!--CRLF-->
import org.apache.mina.core.session.IoSession; <!--CRLF-->
import org.apache.mina.filter.codec.ProtocolCodecFilter; <!--CRLF-->
import org.apache.mina.transport.socket.SocketConnector; <!--CRLF-->
import org.apache.mina.transport.socket.nio.NioSocketConnector; <!--CRLF-->
import com.hoo.mina.client.message.ClientMessageHandlerAdapter; <!--CRLF-->
import com.hoo.mina.code.factory.CharsetCodecFactory; <!--CRLF-->


<!--CRLF-->
/** <!--CRLF-->
* <b>function:</b> mina客户端 <!--CRLF-->
* @author hoojo <!--CRLF-->
* @createDate 2012-6-29 下午07:28:45 <!--CRLF-->
* @file MinaClient.java <!--CRLF-->
* @package com.hoo.mina.client.message <!--CRLF-->
* @project ApacheMiNa <!--CRLF-->
* @blog javascript:void(0) <!--CRLF-->
* @email [email protected] <!--CRLF-->
* @version 1.0 <!--CRLF-->
*/ <!--CRLF-->
public class MinaClient { <!--CRLF-->


<!--CRLF-->
private SocketConnector connector; <!--CRLF-->
private ConnectFuture future; <!--CRLF-->
private IoSession session; <!--CRLF-->


<!--CRLF-->
public boolean connect() { <!--CRLF-->


<!--CRLF-->
// 创建一个socket连接 <!--CRLF-->
connector = new NioSocketConnector(); <!--CRLF-->
// 设置链接超时时间 <!--CRLF-->

connector.setConnectTimeoutMillis(3000);
<!--CRLF-->
// 获取过滤器链 <!--CRLF-->

DefaultIoFilterChainBuilder filterChain = connector.getFilterChain();
<!--CRLF-->
// 添加编码过滤器 处理乱码、编码问题 <!--CRLF-->
filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory())); <!--CRLF-->


<!--CRLF-->
/* <!--CRLF-->
// 日志 <!--CRLF-->
LoggingFilter loggingFilter = new LoggingFilter(); <!--CRLF-->
loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO); <!--CRLF-->
loggingFilter.setMessageSentLogLevel(LogLevel.INFO); <!--CRLF-->
filterChain.addLast("loger", loggingFilter);*/ <!--CRLF-->


<!--CRLF-->
// 消息核心处理器 <!--CRLF-->
connector.setHandler(new ClientMessageHandlerAdapter()); <!--CRLF-->


<!--CRLF-->
// 连接服务器,知道端口、地址 <!--CRLF-->
future = connector.connect(new InetSocketAddress(3456)); <!--CRLF-->
// 等待连接创建完成 <!--CRLF-->

future.awaitUninterruptibly();
<!--CRLF-->
// 获取当前session <!--CRLF-->

session = future.getSession();
<!--CRLF-->
return true; <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public void setAttribute(Object key, Object value) { <!--CRLF-->

session.setAttribute(key, value);
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public void send(String message) { <!--CRLF-->

session.write(message);
<!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public boolean close() { <!--CRLF-->

CloseFuture future = session.getCloseFuture();
<!--CRLF-->

future.awaitUninterruptibly(1000);
<!--CRLF-->

connector.dispose();
<!--CRLF-->
return true; <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public SocketConnector getConnector() { <!--CRLF-->
return connector; <!--CRLF-->

}
<!--CRLF-->


<!--CRLF-->
public IoSession getSession() { <!--CRLF-->
return session; <!--CRLF-->

}
<!--CRLF-->

}

第三步:

完成启动、在控制台输入你发送的内容



package com.hoo.mina.client.main;

<!--CRLF-->


 

<!--CRLF-->


import java.util.Scanner;

<!--CRLF-->


import com.hoo.mina.client.MinaClient;

<!--CRLF-->


 

<!--CRLF-->


/**

<!--CRLF-->


* <b>function:</b> 运行客户端程序

<!--CRLF-->


* @author hoojo

<!--CRLF-->


* @createDate 2012-6-29 下午07:36:44

<!--CRLF-->


* @file RunClient.java

<!--CRLF-->


* @package com.hoo.mina.client.main

<!--CRLF-->


* @project ApacheMiNa

<!--CRLF-->


* @blog javascript:void(0)

<!--CRLF-->


* @email [email protected]

<!--CRLF-->


* @version 1.0

<!--CRLF-->


*/

<!--CRLF-->


public class RunClient {

<!--CRLF-->


 

<!--CRLF-->


public static void main(String[] args) {

<!--CRLF-->


MinaClient client = new MinaClient();

<!--CRLF-->


if (client.connect()) {

<!--CRLF-->


client.send("连接服务器成功!");

<!--CRLF-->


Scanner scanner = new Scanner(System.in);

<!--CRLF-->


while (scanner.hasNext()) {

<!--CRLF-->


client.send(scanner.next());

<!--CRLF-->


}

<!--CRLF-->


}

<!--CRLF-->


}

<!--CRLF-->


}



启动服务器,运行客户端程序可以看到控制台:



2012-08-01 10:01:15,953 INFO [com.hoo.mina.code.CharsetEncoder:34-main] - #############字符编码############

<!--CRLF-->


2012-08-01 10:01:15,953 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########

<!--CRLF-->


2012-08-01 10:01:15,953 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:25-NioProcessor-2] - client receive a message is : welcome to the chat room !

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:29-NioProcessor-2] - messageSent 客户端发送消息:连接服务器成功!

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:25-NioProcessor-2] - client receive a message is : 2012-08-01 10:01:15



服务器控制台:



2012-08-01 10:01:15,921 INFO [com.hoo.mina.server.message.ServerMessageHandler:75-NioProcessor-2] - 创建一个新连接:/192.168.8.22:2644

<!--CRLF-->


2012-08-01 10:01:15,937 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############

<!--CRLF-->


2012-08-01 10:01:15,937 INFO [com.hoo.mina.server.message.ServerMessageHandler:86-NioProcessor-2] - 打开一个session:1#0

<!--CRLF-->


2012-08-01 10:01:15,937 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-2] - 服务器发送消息: welcome to the chat room !

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-2] - 服务器接收到数据: 连接服务器成功!

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-2] - 转发 messageReceived: 2012-08-01 10:01:15 连接服务器成功!

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############

<!--CRLF-->


2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-2] - 服务器发送消息: 2012-08-01 10:01:15 连接服务器成功!

<!--CRLF-->


2012-08-01 10:01:45,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:81-NioProcessor-2] - 当前连接/192.168.8.22:2644处于空闲状态:both idle



在客户端控制台输入聊天内容



hello,MiNaChat~!

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetEncoder:34-main] - #############字符编码############

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:29-NioProcessor-2] - messageSent 客户端发送消息:hello,MiNaChat~!

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:25-NioProcessor-2] - client receive a message is : 2012-08-01 10:03:49



服务器端接收到内容



2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-2] - 服务器接收到数据: hello,MiNaChat~!

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-2] - 转发 messageReceived: 2012-08-01 10:03:49 hello,MiNaChat~!

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############

<!--CRLF-->


2012-08-01 10:03:49,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-2] - 服务器发送消息: 2012-08-01 10:03:49 hello,MiNaChat~!

<!--CRLF-->


2012-08-01 10:04:19,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:81-NioProcessor-2] - 当前连接/192.168.8.22:2644处于空闲状态:both idle



 






作者:​​hoojo​​​        ​


 

标签:hoo,聊天室,01,MiNa,mina,Apache,message,com,2012
From: https://blog.51cto.com/kenkao/6000378

相关文章

  • Apache Spark + 海豚调度:PB 级数据调度挑战,教你如何构建高效离线工作流
    2010年,我国进入移动互联网,数据规模成几何式增长。在大数据开源技术领域,以Hadoop为核心的大数据生态系统面对海量数据也不断发展与迭代,大数据处理流程中的各个开源组件,也一起......
  • Apache Kafka 的基本概念
    基本概念主题Topictopic是Kafka最基础的组织单位,类似于关系数据库中的数据表。做为使用kafka的开发者,你最应该考虑的是和topoc相关的抽象。创建不同的topic保......
  • terminal 终端美化
    编辑PowerShell配置文件脚本,每次启动之后自动加载notepad$PROFILE在配置文件里添加以下行:oh-my-poshinitpwsh--config'$env:POSH_THEMES_PATH\jandedobbeleer.o......
  • Apache Log4j2 RCE漏洞复现
    看我看我,有没有大佬悄咪咪的给我个exp打自己过过瘾漏洞描述ApacheLog4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日......
  • 快速部署Apache服务静态网站
    Apache是世界使用排名第一的Web服务器软件.它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一.它快速、可靠并且......
  • 中间件漏洞——apache
    解析漏洞1、php配置引起的扩展名解析漏洞在mod_php与apache的模式下会出现该漏洞。该模式下php作为apache的子模块对代码进行解析,遇到匹配下面代码规则的文件,则继续当做......
  • 关于org.apache.ibatis.binding.BindingException: Invalid bound statement (not fou
    需要检查的地方:1.是否mapper.java文件上使用了注解@Mapper 或者在启动类上扫描了Mapper类@MapperScan("com.heima.model.mappers") 【注意扫描的包名是否正确】2.......
  • windows terminal 1.12配置
    {"$help":"https://aka.ms/terminal-documentation","$schema":"https://aka.ms/terminal-profiles-schema","actions":[{"......
  • Apache Pulsar——Java API操作tenant、namespace、topic
    一、添加pom.xml依赖<dependency> <groupId>org.apache.pulsar</groupId> <artifactId>pulsar-client</artifactId> <version>2.10.0</version></dependency>二、ten......
  • Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:tes
    报错Failedtoexecutegoalorg.apache.maven.plugins:maven-surefire-plugin:2.22.2:test(default-test)onprojectdemo2:Therearetestfailures.问题原因:......