设为首页 收藏本站
查看: 1638|回复: 0

[经验分享] Apache MiNa 实现多人聊天室

[复制链接]

尚未签到

发表于 2015-7-30 16:07:06 | 显示全部楼层 |阅读模式

  开发环境:
  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.iyunv.com/IBM_hoojo
  http://hoojo.iyunv.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如下
DSC0000.jpg   如果你使用日志,需要添加日志配置文件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; /** * function: 字符编码、解码工厂类,编码过滤工厂 * @author hoojo * @createDate 2012-6-26 下午01:08:50 * @file CharsetCodecFactory.java * @package com.hoo.mina.code.factory * @project ApacheMiNa * @blog http://blog.iyunv.com/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; /** * function: 字符解码 * @author hoojo * @createDate 2012-6-26 上午11:14:18 * @file CharsetDecoder.java * @package com.hoo.mina.code * @project ApacheMiNa * @blog http://blog.iyunv.com/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; /** * function: 字符编码 * @author hoojo * @createDate 2012-6-26 上午11:32:05 * @file CharsetEncoder.java * @package com.hoo.mina.code * @project ApacheMiNa * @blog http://blog.iyunv.com/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; /** * function: 处理服务器端消息 * @author hoojo * @createDate 2012-6-26 下午01:12:34 * @file ServerMessageHandler.java * @package com.hoo.mina.server.message * @project ApacheMiNa * @blog http://blog.iyunv.com/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 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() {            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:会话被关闭;
  状态转换图如下: DSC0001.jpg


  第四步:
  编写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; /** * function: 服务器启动类 * @author hoojo * @createDate 2012-6-29 下午07:11:00 * @file MinaServer.java * @package com.hoo.mina.server * @project ApacheMiNa * @blog http://blog.iyunv.com/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:25422012-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#02012-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.12012-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.12012-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:34562012-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:34562012-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.12012-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.12012-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.82012-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; /** * function: 客户端消息处理类 * @author hoojo * @createDate 2012-6-29 下午07:24:22 * @file ClientMessageHandlerAdapter.java * @package com.hoo.mina.client.message * @project ApacheMiNa * @blog http://blog.iyunv.com/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; /** * function: mina客户端 * @author hoojo * @createDate 2012-6-29 下午07:28:45 * @file MinaClient.java * @package com.hoo.mina.client.message * @project ApacheMiNa * @blog http://blog.iyunv.com/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; /** * function: 运行客户端程序 * @author hoojo * @createDate 2012-6-29 下午07:36:44 * @file RunClient.java * @package com.hoo.mina.client.main * @project ApacheMiNa * @blog http://blog.iyunv.com/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:26442012-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#02012-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  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-92385-1-1.html 上篇帖子: XAMPP中Apache无法启动 下篇帖子: 【转】apache common
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表