Apache MiNa 實現多人聊天室


開發環境:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM