Mina入門實例(一)


mina現在用的很多了,之前也有用到,但是畢竟不熟悉,於是查了一些資料,做了一些總結。看代碼是最直觀的,比什么長篇大論都要好。不過其中重要的理論,也要理解下。

首先是環境,程序運行需要幾個包,這里用maven比較方便。

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>MyMinaServer</groupId>
  <artifactId>mina</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mina</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
      <dependency>  
            <groupId>org.apache.mina</groupId>  
            <artifactId>mina-core</artifactId>  
            <version>2.0.4</version>  
        </dependency>  
  
        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>jcl-over-slf4j</artifactId>  
            <version>1.6.1</version>  
        </dependency>  
  
        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>slf4j-nop</artifactId>  
            <version>1.6.1</version>  
        </dependency>  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

然后就可以寫代碼了。

---------------------------------------------------------- 分割線 -----------------------------------------------------------------------------------------

一,簡單的客戶端和服務端程序

服務端程序:

package MyMinaServer.mina;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class MainServer {
    private static final int Port=8888;
    public static void main(String[] args) {
        IoAcceptor ioAcceptor=new NioSocketAcceptor();
        System.out.println("begin server....");
        ioAcceptor.getFilterChain().addLast("logger", new LoggingFilter());
        ioAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
        ioAcceptor.setHandler(new HelloWorldHandler());
        ioAcceptor.getSessionConfig().setReadBufferSize(2048);
        ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
        try {
            ioAcceptor.bind(new InetSocketAddress(Port));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

服務端,創建連接,然后這里注冊了幾個過濾鏈,這里簡單寫了需要的兩個,到后面的內容中還可以加入一個加密的ssl鏈。

其中重要的是setHandler這個,在這個里面,我們可以定義自己的handler,然后做自己的業務。下面有這個handler的簡單代碼。

最后設置session的緩沖,和idle(空閑處理)的設定,再為此連接綁定一個端口。

其中需要注意的是,在服務端和客戶端的代碼里面,如果要傳遞string信息,codec編碼過濾器中,要這么寫:new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))。否則報錯。

業務處理的handler:

package MyMinaServer.mina;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

public class HelloWorldHandler extends IoHandlerAdapter{

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        // TODO Auto-generated method stub
        super.exceptionCaught(session, cause);
    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        // TODO Auto-generated method stub
        String string=message.toString();
        if (string.trim().equalsIgnoreCase("quit")) {
            session.close(true);
            return;
        }
        System.out.println("recevied message:"+string);
        String reply=" hi, i am server";
        session.write(reply);
        System.out.println("message have been written");
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("message have been sent");
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("closed session");
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("session created");
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("IDLE "+session.getIdleCount(status));
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("session opened");
    }

}

這里的每個方法,算是事件。在每個事件中,我們可以定義自己的處理。在前面的《AndroidPn源碼分析(一)》這篇文章中,筆者曾寫過他們的每個事件代表的含義,不過從字面意思也很好理解。

這里主要是對接受到信息的處理,如果不是收到quit字符,則返回給客戶端一句 hi,i am server。

服務端暫時到此,以下是客戶端。

package com.example.mina.server;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

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.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.example.mina.charset.CharsetFactory;
import com.example.mina.hanlder.MsgHanler;public class MinaClient {

    private SocketConnector connector;
    private ConnectFuture future;
    private IoSession session;

    public boolean connect() {
        /*
         * 1.創建一個socket連接,連接到服務器
         */
        connector = new NioSocketConnector();

        /*
         * 獲取過濾器鏈,用於添加過濾器
         */
        DefaultIoFilterChainBuilder chain = connector.getFilterChain();

        // b.添加日志過濾器
        chain.addLast("logger", new LoggingFilter());

        // c.添加字符的編碼過濾器
        chain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

        /*
         * 3.設置消息處理器,用於處理接收到的消息
         */
        connector.setHandler(new MsgHanler());

        /*
         * 4.根據IP和端口號連接到服務器
         */
        future = connector.connect(new InetSocketAddress("127.0.0.1", 8888));
        // 等待連接創建完成
        future.awaitUninterruptibly();

        /*
         * 5.獲取session對象,通過session可以向服務器發送消息;
         */
        session = future.getSession();
        session.getConfig().setUseReadOperation(true);
        return future.isConnected();
    }

    /**
     * 往服務器發送消息
     * 
     * @param message
     */
    public void sendMsg2Server(String message) {
        session.write(message);
    }

    /**
     * 關閉與服務器的連接
     * 
     * @return
     */
    public boolean close() {
        CloseFuture future = session.getCloseFuture();
        future.awaitUninterruptibly(1000);
        connector.dispose();
        return true;
    }
}

然后同樣是一個客戶端的handler,和server的很像:

package com.example.mina.hanlder;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MsgHanler extends IoHandlerAdapter {
    private static final Logger log = LoggerFactory.getLogger(MsgHanler.class);

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        // 出現異常
        log.error("--------exception--------");
        super.exceptionCaught(session, cause);
    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        // 從服務器中接收到消息后的處理
        log.info("--------msg receive--------");
        log.info("Message:{}" + message.toString());
        super.messageReceived(session, message);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        // 往服務器中發送消息
        log.info("--------msg sent--------");
        super.messageSent(session, message);
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        // 當session被創建的時候調用
        log.info("--------session create--------");
        super.sessionCreated(session);
    }
}

寫一個入口方法:

package com.example.mina.server;

public class Main {

    public static void main(String[] args) {
        MinaClient client=new MinaClient();
        client.connect();
        client.sendMsg2Server("message from cilent");
    }
}

這樣,客戶端就可以工作了。

先啟動服務端,然后啟動客戶端,就可以看到在兩個控制台中,分別有交互信息。

服務端:

begin server....
session created
session opened
recevied message:message from cilent
message have been written
message have been sent

客戶端:

[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(186) | CREATED
[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.sessionCreated(54) | --------session create--------
[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(186) | OPENED
[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(157) | SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageSent(47) | --------msg sent--------
[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(157) | RECEIVED: HeapBuffer[pos=0 lim=17 cap=2048: 20 68 69 2C 20 69 20 61 6D 20 73 65 72 76 65 72...]
[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageReceived(39) | --------msg receive--------
[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageReceived(40) | Message:{} hi, i am server

客戶端因為用了log4j,打印比較多信息。

到此,這個例子就完成了。

 


免責聲明!

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



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