Apache MiNa 实现多人聊天室

来源:互联网 发布:遗传算法排课java代码 编辑:程序博客网 时间:2024/06/07 05:32

开发环境:

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

Email:hoojo_@126.com

Blog:http://blog.csdn.net/IBM_hoojo

http://hoojo.cnblogs.com/

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如下

clip_image002

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

第二步:

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

package com.hoo.mina.code.factory;
 
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 com.hoo.mina.code.CharsetDecoder;
import com.hoo.mina.code.CharsetEncoder;
 
/**
 * <b>function:</b> 字符编码、解码工厂类,编码过滤工厂
 * @author hoojo
 * @createDate 2012-6-26 下午01:08:50
 * @file CharsetCodecFactory.java
 * @package com.hoo.mina.code.factory
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
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();
    }
}

解码类

package com.hoo.mina.code;
 
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
 
/**
 * <b>function:</b> 字符解码
 * @author hoojo
 * @createDate 2012-6-26 上午11:14:18
 * @file CharsetDecoder.java
 * @package com.hoo.mina.code
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class CharsetDecoder implements ProtocolDecoder {
 
    private final static Logger log = Logger.getLogger(CharsetDecoder.class);
    
    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.info("#########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.info("message: " + message);
            } else {
                buff.put(b);
            }
        }
    }
 
    @Override
    public void dispose(IoSession session) throws Exception {
        log.info("#########dispose#########");
        log.info(session.getCurrentWriteMessage());
    }
 
    @Override
    public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
        log.info("#########完成解码#########");
    }
}

上面的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;
 
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
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 org.apache.mina.filter.codec.textline.LineDelimiter;
 
/**
 * <b>function:</b> 字符编码
 * @author hoojo
 * @createDate 2012-6-26 上午11:32:05
 * @file CharsetEncoder.java
 * @package com.hoo.mina.code
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class CharsetEncoder implements ProtocolEncoder {
    private final static Logger log = Logger.getLogger(CharsetEncoder.class);
    private final static Charset charset = Charset.forName("UTF-8");
    
    @Override
    public void dispose(IoSession session) throws Exception {
        log.info("#############dispose############");
    }
 
    @Override
    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
        log.info("#############字符编码############");
        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);
    }
}

第三步:

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

package com.hoo.mina.server.message;
 
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * <b>function:</b> 处理服务器端消息
 * @author hoojo
 * @createDate 2012-6-26 下午01:12:34
 * @file ServerMessageHandler.java
 * @package com.hoo.mina.server.message
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class ServerMessageHandler implements IoHandler {
    
    private final static Logger log = LoggerFactory.getLogger(ServerMessageHandler.class);
    
    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        log.info("服务器发生异常: {}", cause.getMessage());
    }
 
    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        log.info("服务器接收到数据: {}", message);
        String content = message.toString();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String datetime = sdf.format(new Date());
        
        log.info("转发 messageReceived: " + datetime + "\t" + content);
        
        // 拿到所有的客户端Session
        Collection<IoSession> sessions = session.getService().getManagedSessions().values();
        // 向所有客户端发送数据
        for (IoSession sess : sessions) {
            sess.write(datetime + "\t" + content);
        }
    }
 
    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        log.info("服务器发送消息: {}", message);
    }
 
    @Override
    public void sessionClosed(IoSession session) throws Exception {
        log.info("关闭当前session:{}#{}", session.getId(), session.getRemoteAddress());
        
        CloseFuture closeFuture = session.close(true);
        closeFuture.addListener(new IoFutureListener<IoFuture>() {
            public void operationComplete(IoFuture future) {
                if (future instanceof CloseFuture) {
                    ((CloseFuture) future).setClosed();
                    log.info("sessionClosed CloseFuture setClosed-->{},", future.getSession().getId());
                }
            }
        });
    }
 
    @Override
    public void sessionCreated(IoSession session) throws Exception {
        log.info("创建一个新连接:{}", session.getRemoteAddress());
        session.write("welcome to the chat room !");
    }
 
    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        log.info("当前连接{}处于空闲状态:{}", session.getRemoteAddress(), status);
    }
 
    @Override
    public void sessionOpened(IoSession session) throws Exception {
        log.info("打开一个session:{}#{}", session.getId(), session.getBothIdleCount());
    }
}

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:会话被关闭;

状态转换图如下:

clip_image004

第四步:

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

package com.hoo.mina.server;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import com.hoo.mina.code.factory.CharsetCodecFactory;
import com.hoo.mina.server.message.ServerMessageHandler;
 
/**
 * <b>function:</b> 服务器启动类
 * @author hoojo
 * @createDate 2012-6-29 下午07:11:00
 * @file MinaServer.java
 * @package com.hoo.mina.server
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class MinaServer {
    
    private SocketAcceptor acceptor;
    
    public MinaServer() {
        // 创建非阻塞的server端的Socket连接
        acceptor = new NioSocketAcceptor();
    }
    
    public boolean start() {
        DefaultIoFilterChainBuilder filterChain = acceptor.getFilterChain();
        // 添加编码过滤器 处理乱码、编码问题
        filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
        
        /*LoggingFilter loggingFilter = new LoggingFilter();
        loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO);
        loggingFilter.setMessageSentLogLevel(LogLevel.INFO);
        // 添加日志过滤器
        filterChain.addLast("loger", loggingFilter);*/
        
        // 设置核心消息业务处理器
        acceptor.setHandler(new ServerMessageHandler());
        // 设置session配置,30秒内无操作进入空闲状态
        acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
        
        try {
            // 绑定端口3456
            acceptor.bind(new InetSocketAddress(3456));
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    public static void main(String[] args) {
        MinaServer server = new MinaServer();
        server.start();
    }
}

上面的代码主要完成启动参数的设置,如端口、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
2012-08-01 09:55:56,046 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:86-NioProcessor-1] - 打开一个session:3#0
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-1] - 服务器发送消息: welcome to the chat room !
2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-1] - #########decode#########
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: GET / HTTP/1.1
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
2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
2012-08-01 09:55:56,062 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-1] - 服务器接收到数据: Host: localhost:3456
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
2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
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
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
2012-08-01 09:55:56,062 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-1] - #############字符编码############
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
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
其他内容省略……

三、客户端编码工作

第一步:

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

package com.hoo.mina.client.message;
 
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * <b>function:</b> 客户端消息处理类
 * @author hoojo
 * @createDate 2012-6-29 下午07:24:22
 * @file ClientMessageHandlerAdapter.java
 * @package com.hoo.mina.client.message
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class ClientMessageHandlerAdapter extends IoHandlerAdapter {
 
    private final static Logger log = LoggerFactory.getLogger(ClientMessageHandlerAdapter.class);
    
    public void messageReceived(IoSession session, Object message) throws Exception {
        String content = message.toString();
        log.info("client receive a message is : " + content);
    }
    
    public void messageSent(IoSession session , Object message) throws Exception{
        log.info("messageSent 客户端发送消息:" + message);
    }
    
    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        log.info("服务器发生异常: {}", cause.getMessage());
    }
}

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

第二步:

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

package com.hoo.mina.client;
 
import java.net.InetSocketAddress;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import com.hoo.mina.client.message.ClientMessageHandlerAdapter;
import com.hoo.mina.code.factory.CharsetCodecFactory;
 
/**
 * <b>function:</b> mina客户端
 * @author hoojo
 * @createDate 2012-6-29 下午07:28:45
 * @file MinaClient.java
 * @package com.hoo.mina.client.message
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class MinaClient {
 
    private SocketConnector connector;
    private ConnectFuture future;
    private IoSession session;
 
    public boolean connect() {
 
        // 创建一个socket连接
        connector = new NioSocketConnector();
        // 设置链接超时时间
        connector.setConnectTimeoutMillis(3000);
        // 获取过滤器链
        DefaultIoFilterChainBuilder filterChain = connector.getFilterChain();
        // 添加编码过滤器 处理乱码、编码问题
        filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
 
        /*
        // 日志
        LoggingFilter loggingFilter = new LoggingFilter();
        loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO);
        loggingFilter.setMessageSentLogLevel(LogLevel.INFO);
        filterChain.addLast("loger", loggingFilter);*/
 
        // 消息核心处理器
        connector.setHandler(new ClientMessageHandlerAdapter());
 
        // 连接服务器,知道端口、地址
        future = connector.connect(new InetSocketAddress(3456));
        // 等待连接创建完成
        future.awaitUninterruptibly();
        // 获取当前session
        session = future.getSession();
        return true;
    }
 
    public void setAttribute(Object key, Object value) {
        session.setAttribute(key, value);
    }
 
    public void send(String message) {
        session.write(message);
    }
 
    public boolean close() {
        CloseFuture future = session.getCloseFuture();
        future.awaitUninterruptibly(1000);
        connector.dispose();
        return true;
    }
 
    public SocketConnector getConnector() {
        return connector;
    }
 
    public IoSession getSession() {
        return session;
    }
}

第三步:

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

package com.hoo.mina.client.main;
 
import java.util.Scanner;
import com.hoo.mina.client.MinaClient;
 
/**
 * <b>function:</b> 运行客户端程序
 * @author hoojo
 * @createDate 2012-6-29 下午07:36:44
 * @file RunClient.java
 * @package com.hoo.mina.client.main
 * @project ApacheMiNa
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class RunClient {
 
    public static void main(String[] args) {
        MinaClient client = new MinaClient();
        if (client.connect()) {
            client.send("连接服务器成功!");
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                client.send(scanner.next());
            }
        }
    }
}

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

2012-08-01 10:01:15,953 INFO [com.hoo.mina.code.CharsetEncoder:34-main] - #############字符编码############
2012-08-01 10:01:15,953 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########
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 !
2012-08-01 10:01:15,984 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:29-NioProcessor-2] - messageSent 客户端发送消息:连接服务器成功!
2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########
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
2012-08-01 10:01:15,937 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############
2012-08-01 10:01:15,937 INFO [com.hoo.mina.server.message.ServerMessageHandler:86-NioProcessor-2] - 打开一个session:1#0
2012-08-01 10:01:15,937 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-2] - 服务器发送消息: welcome to the chat room !
2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########
2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-2] - 服务器接收到数据: 连接服务器成功!
2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:43-NioProcessor-2] - 转发 messageReceived: 2012-08-01 10:01:15    连接服务器成功!
2012-08-01 10:01:15,984 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############
2012-08-01 10:01:15,984 INFO [com.hoo.mina.server.message.ServerMessageHandler:55-NioProcessor-2] - 服务器发送消息: 2012-08-01 10:01:15    连接服务器成功!
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~!
2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetEncoder:34-main] - #############字符编码############
2012-08-01 10:03:49,093 INFO [com.hoo.mina.client.message.ClientMessageHandlerAdapter:29-NioProcessor-2] - messageSent 客户端发送消息:hello,MiNaChat~!
2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetDecoder:31-NioProcessor-2] - #########decode#########
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#########
2012-08-01 10:03:49,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:38-NioProcessor-2] - 服务器接收到数据: hello,MiNaChat~!
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~!
2012-08-01 10:03:49,093 INFO [com.hoo.mina.code.CharsetEncoder:34-NioProcessor-2] - #############字符编码############
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~!
2012-08-01 10:04:19,093 INFO [com.hoo.mina.server.message.ServerMessageHandler:81-NioProcessor-2] - 当前连接/192.168.8.22:2644处于空闲状态:both idle
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 马自达8停产后配件怎么办 钢铁雄心3没将领怎么办 江苏低于二本线怎么办 电工证快过期了怎么办 天正建筑打不开高版本的图纸怎么办 打开天正只显示cad怎么办 天正软件显示过期了怎么办 四岁宝宝经常吐怎么办 穿越火线登陆不上去怎么办 猫猫呕吐带血怎么办 狗又吐又拉稀怎么办 狗狗肠炎拉血怎么办 拉大便有血怎么办呢 工作中遇到不公待遇怎么办 老兵丢了退伍证怎么办 我的退伍证丢了怎么办 退伍证丢了怎么办啊 银行卡更换之前的卡号怎么办 收到联通欠费催款律师函怎么办 苹果5s玩王者卡怎么办 电信宽带包年用户欠费怎么办 员工不处理考勤异常怎么办 移动号码特殊原因强制停机怎么办 下雨天我怎么办我好想你 免检标志领晚了怎么办 激光点太田痣揉搓了泛红怎么办 花束与衣服颜色相称怎么办 吃鸡狙击枪距离怎么办 环世界敌人炸墙怎么办 水阀断在墙里面怎么办 内陷螺丝扣秃了怎么办 五菱仪表盘不亮怎么办 瞒着老婆欠了钱怎么办 m8螺丝牙距孔距差一个毫米怎么办 内丝弯头坏了怎么办 螺纹底孔打大了怎么办 内螺纹止规过了怎么办 牌照螺丝装错了怎么办 帽式扳手大了怎么办 内六角扳手小了怎么办 内六角扳手不够大怎么办?