`

Apache MiNa 实现多人聊天室

    博客分类:
  • Java
阅读更多

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;
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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:会话被关闭;

状态转换图如下:

clip_image004

第四步:

编写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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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-->
其他内容省略……
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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 http://blog.csdn.net/IBM_hoojo
<!--CRLF-->
 * @email hoojo_@126.com
<!--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-->
}
<!--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
<!--CRLF-->

服务器控制台:

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
<!--CRLF-->

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

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
<!--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.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
<!--CRLF-->

 



作者:hoojo
出处: http://www.blogjava.net/hoojo/archive/2012/08/01/384490.html
blog:http://blog.csdn.net/IBM_hoojo
         http://hoojo.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

分享到:
评论

相关推荐

    apache mina实现多人聊天室

    总的来说,通过Apache Mina实现的多人聊天室项目,不仅展示了Mina如何处理网络通信,还涉及到并发编程、协议解析、过滤器链等多方面的技术知识。对于学习和理解网络编程以及Mina框架的工作原理,这是一个非常有价值...

    mina实现多人聊天工程源码

    《基于Mina实现的多人聊天系统详解》 Mina(Java Multithreaded Network Application Framework)是一个开源的网络通信框架,由Apache软件基金会开发。它为开发者提供了构建高性能、高可用性的网络应用的强大工具,...

    mina+spring实现多人聊天室程序

    Mina框架和Spring框架的结合,为开发者提供了一种高效、灵活的方式来实现这样的系统,特别是多人聊天室程序。下面我们将详细探讨如何利用这两个强大的工具来构建一个稳定且功能丰富的聊天室应用。 Mina框架,全称...

    MINA框架 多人聊天的技术原型 包含slf4j和Log4j配置

    本技术原型主要展示了如何利用MINA来实现一个多人聊天系统。在这个项目中,MAVEN作为项目管理和构建工具,负责依赖管理、构建流程以及插件应用,确保项目的标准化和可维护性。MAVEN通过其pom.xml文件来定义项目依赖...

    Apache Mina Server 2.0中文参考手册V1.0,Apache Mina2.0学习笔记(修订版)

    Apache Mina Server 2.0中文参考手册V1.0,Apache Mina2.0学习笔记(修订版)Apache Mina Server 2.0中文参考手册V1.0,Apache Mina2.0学习笔记(修订版)

    apache-mina-2.0.4.rar_apache mina_mina

    Apache Mina是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。这个"apache-mina-2.0.4.rar"压缩包包含的是Apache Mina 2.0.4版本的源代码,是深入理解和定制Mina的...

    基于Apache Mina实现的TCP长连接和短连接实例

    在这个实例中,我们将深入探讨如何利用Apache Mina实现TCP的长连接和短连接。 首先,TCP(传输控制协议)是互联网上广泛使用的面向连接的协议,它保证了数据的可靠传输。TCP连接分为两种类型:长连接和短连接。 1....

    apache Mina的完整学习资料

    随着对Mina理解的深入,你可以尝试实现更复杂的网络应用,如FTP服务器、聊天室等。 学习Apache Mina的过程中,建议关注以下几点: 1. **实战项目**:结合实际需求创建项目,通过实践巩固理论知识。 2. **性能优化**...

    Apache Mina帮助文档

    Apache Mina是一个高度可扩展的网络通信框架,主要用于构建高性能、高效率的服务端应用程序。它提供了事件驱动、异步I/O处理模型,使得开发者能够更专注于业务逻辑,而不是底层网络编程的复杂性。Mina主要应用于Java...

    关于apache Mina Server

    深入理解Apache_Mina_(1)----_Mina的几个类 深入理解Apache_Mina_(2)----_与IoFilter相关的几个类 深入理解Apache_Mina_(3)----_与IoHandler相关的几个类 深入理解Apache_Mina_(4)----_IoFilter和IoHandler的区别和...

    mina写的聊天室

    总而言之,Mina聊天室是一个利用Apache Mina构建的实时通信应用,它展示了如何利用Mina框架处理网络通信,以及如何与图形用户界面集成以实现一个完整的聊天系统。开发这样的应用需要理解Mina的I/O模型,熟悉Java多...

    apache mina 学习笔记三(子项目FtpServer)

    Apache MINA FtpServer提供了一个可扩展且高效的FTP服务器实现,允许开发人员自定义认证机制、数据存储策略以及许多其他特性。 **FtpServer基本架构** Apache MINA FtpServer的核心组件包括服务器引擎、服务器端口...

    apache mina实例免费下载

    在实际应用中,Apache MINA常用于构建服务器端应用,如聊天服务器、游戏服务器、文件传输服务等。通过MINA提供的API,开发者可以轻松创建出处理大量并发连接的服务。MINA实例通常包含以下部分: 1. **Acceptor**:...

    Apache Mina 入门Demo

    Apache Mina是一个开源项目,主要用于构建高性能、高可用性的网络通信应用。它是Java语言开发的,提供了一套简单而强大的API,使得开发者可以方便地创建网络服务器和客户端应用程序。Mina的目标是简化网络编程,使其...

    Apache mina2学习笔记DEMO

    Apache MINA(Multipurpose Infrastructure for Network Applications)是一个Java框架,专为高性能、异步网络应用程序设计。MINA 提供了一套高级的网络通信抽象层,简化了开发过程,特别是对于处理TCP/IP和UDP/IP...

    Apache MINA框架相关资料

    Apache MINA(Multipurpose Infrastructure for Network Applications)是一个高性能、异步事件驱动的网络应用程序框架,主要用于简化开发高质量的网络服务。这个框架适用于多种协议,如TCP/IP和UDP/IP,以及NIO(非...

    Apache MINA 2.0 用户指南( 缺第一章节)

    ### Apache MINA 2.0 用户指南:基础知识 #### 基础概念介绍 Apache MINA 2.0 是一款高性能且易于使用的网络应用程序框架,它简化了开发人员在网络编程方面的负担,允许开发者专注于应用程序的核心功能,而不是底层...

    Apache Mina Server 2.0 抢鲜体验

    Apache Mina Server 2.0 是一款高性能、可扩展的网络通信框架,广泛应用于开发网络应用服务器,如TCP/IP和UDP服务。这个框架允许开发者用Java编写高效的网络应用程序,简化了网络编程的复杂性。Mina 2.0 版本在前一...

    Apache Mina核心jar包:mina-core-2.0.7

    Apache MINA是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。 当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版...

Global site tag (gtag.js) - Google Analytics