MINA 实战

编写MINA简单版是很简单的,甚至你连客户端都不用写了,直接就写服务端,然后用telnet远程链接服务端端口就行了。但是,我这里把服务端和客户端都实现了,先看看项目类结构。
这里写图片描述

代码如下:

服务端处理器

package com.chen.server;
import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

import java.util.Date;
/**
 * Created by CHEN on 2016/8/5.
 * 这个类继承了IO接收的适配器,是IO接收的适配器实现
 * 定义了大量的session动作
 * 最重要的时候messageReceived
 */

public class Demo1ServerHandler extends IoHandlerAdapter {

    public static Logger logger = Logger.getLogger(Demo1ServerHandler.class);

    public void sessionCreated(IoSession session) throws Exception {
        logger.info("服务端与客户端创建连接");
    }

    public void sessionOpened(IoSession session) throws Exception {
        logger.info("服务器与客户端连接打开...");
    }

    /**
     *
     * @param session
     * @param message
     * @throws Exception
     */
    public void messageReceived(IoSession session, java.lang.Object message) throws Exception {
        String msg = message.toString();
        logger.info("服务端接收的数据为:" + msg);
        if ("bye".equals(msg)) {//服务器断开的条件
            session.close(true);
        }
        Date date = new Date();
        session.write(date+msg);
    }

    public void messageSent(IoSession session, Object message) throws Exception {
        logger.info("服务端发送消息成功...");
    }

    public void sessionIdle(IoSession session, IdleStatus status) throws java.lang.Exception {
        logger.error("服务端进入空闲状态...");
    }

    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        logger.error("服务端发送异常...", cause);
    }

    public void sessionClosed(IoSession session) throws Exception {
        logger.info("关闭连接...");
    }

}

服务端

package com.chen.server;

import org.apache.log4j.Logger;
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.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

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

/**
 * Created by CHEN on 2016/8/5.
 */
public class DemoServer {

    private static Logger logger = Logger.getLogger(DemoServer.class);

    private static int PORT = 3025;

    public static void main(String[] args) {
        //创建非阻塞的server端的socket
        IoAcceptor acceptor = null;
        try {
            //因为程序是基于TCP/IP,所以我们添加一个SocketAcceptor,用来接收客户端的请求
            acceptor = new NioSocketAcceptor();
            // 设置日志过滤器
            //这个过滤器将会日志记录所有信息,
            // 比如 session 的新建、接收到的消息、发送的消息、session 的关闭。
            // 接下来的过滤器是一个 ProtocolCodecFilter。
            // 这个过滤器将会把二进制或者协议特定的数据翻译为消息对象,反之亦然。
            // 我们使用一个现有的 TextLine 工厂因为它将为你处理基于文本的消息
            // (你无须去编写 codec 部分)。
            acceptor.getFilterChain().addLast("logger",new LoggingFilter());
            acceptor.getFilterChain().addLast(   //添加消息过滤器
                    "codec",
                    //Mina自带的根据文本换行符编解码的TextLineCodec过滤器 看到\r\n就认为一个完整的消息结束了
                    new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),
                            LineDelimiter.WINDOWS.getValue(),
                            LineDelimiter.WINDOWS.getValue()
                    )));

            //设置读取数据的缓冲区的大小
            acceptor.getSessionConfig().setReadBufferSize(2048);
            //读取通道10s内无操作进入空闲状态
            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
            //绑定逻辑处理器
            acceptor.setHandler(new Demo1ServerHandler());
            //绑定端口
            acceptor.bind(new InetSocketAddress(PORT));
            logger.info("服务器启动成功.. 端口号为:" + PORT);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

客户端处理器

package com.chen.client;

/**
 * Created by CHEN on 2016/8/5.
 */

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

public class Demo1ClientHandler extends IoHandlerAdapter {

    private static Logger logger = Logger.getLogger(Demo1ClientHandler.class);

    public void messageReceived(IoSession session, Object message)
            throws Exception {
        String msg = message.toString();
        logger.info("客户端接收到的信息为:" + msg);
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        logger.error("客户端发生异常...", cause);
    }

    /**
     * TODO 考虑重连的问题
     * @param session
     * @throws Exception
     */
    @Override
    public void sessionClosed(IoSession session) throws Exception {

     /*   try {
            int failCount = 0;
            while (true) {
                Thread.sleep();
                System.out.println(((InetSocketAddress) connector.getDefaultRemoteAddress()).getAddress()
                        .getHostAddress());
                ConnectFuture future = connector.connect();
                System.out.println("断线2");
                future.awaitUninterruptibly();// 等待连接创建完成
                System.out.println("断线3");
                session = future.getSession();// 获得session
                System.out.println("断线4");
                if (session != null && session.isConnected()) {
                    System.out.println("断线5");
                    System.out.println("断线重连["
                            + ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress()
                            + ":" + ((InetSocketAddress) session.getRemoteAddress()).getPort() + "]成功");
                    session.write("start");
                    break;
                } else {
                    System.out.println("断线重连失败---->" + failCount + "次");
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }*/

    }
}

客户端

package com.chen.client;

/**
 * Created by CHEN on 2016/8/5.
 */
import org.apache.log4j.Logger;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
public class MinaClient0 {

    private static Logger logger = Logger.getLogger(MinaClient0.class);

    private static String HOST = "127.0.0.1";

    private static int PORT = 3025;

    public static void main(String[] args) {
        //创建一个非阻塞的客户端
        IoConnector connector = new NioSocketConnector();
        //设置链接超时时间
        connector.setConnectTimeoutMillis(30000);
        //添加过滤器
        connector.getFilterChain().addLast(   //添加消息过滤器
                "codec",
                //Mina自带的根据文本换行符编解码的TextLineCodec过滤器 看到\r\n就认为一个完整的消息结束了
                new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),
                        LineDelimiter.WINDOWS.getValue(),
                        LineDelimiter.WINDOWS.getValue()
                )));
        //添加业务逻辑处理器类
        connector.setHandler(new Demo1ClientHandler());
        IoSession session = null;
        try {
            ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));
            future.awaitUninterruptibly(); //等待连接创建完成
            session = future.getSession();
            //发送信息
            while(true){
                BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
                session.write(in.readLine());
            }


            //session.write("我爱你mina");
        } catch (Exception e) {
            logger.error("客户端链接异常...", e);
        }

        session.getCloseFuture().awaitUninterruptibly();
        logger.info("我们要关闭了");
        connector.dispose();
    }
}

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>com.chen</groupId>
  <artifactId>main</artifactId>
  <version>1.0-SNAPSHOT</version>
  <modules>
    <module>../spring_mina</module>
    <module>../mina_http</module>
    <module>../test_h2</module>
  </modules>
  <packaging>pom</packaging>

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

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

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.apache.mina/mina-core -->
    <dependency>
      <groupId>org.apache.mina</groupId>
      <artifactId>mina-core</artifactId>
      <version>2.0.13</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.12</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

MINA 指南

Mina介绍:https://blog.csdn.net/haoranhaoshi/article/details/89102597 工程内容介绍(由浅入深,稳扎稳打): test1:建立Server和Client。有Client加入,Server广播给所有Client。 test2:在控制台中Server可以给所有Client发送数据,Client可以给Sever和其他Client发送数据。 test3:(1)特定角色的Client处理消息。 (2)特定角色的Client收到消息。 Client与Server建立Session后,Server存储Client的Role和Session映射(同一个角色可映射多个Session)。角色Role在MinaClientHandler中。修改Role,启动多个Client测试。Client在控制台中Role:Message的格式给对应Role的Client发送Message。 test4:(1)Client启动时如果没有Server,就先建立Server。在test3(2)基础上修改MinaClient的session = future.getSession();即可。 (2)如果建立Server的Client离开了,让另一个Client建立Server。 (3)Client给Server发送数据,如果失败,重新发送。 test5:一个Client有一个Server。Client和其他Client的Server建立Session。 test6:如果Client连接Server失败,就只建立Server,如果Server离开,第一个检测到的Client建立Server。 一个进程中包括Server和Client,进程A和B通信,Server负责接收另一个进程的消息,Client负责发送给另一个进程消息,无需Server独立启动,或者绑定在一个进程中,保证最后离线,或者绑定在一个进程中,进程离线后绑定在其他进程中。把Client中的OWN_SERVER_PORT和ANOTHER_SERVER_PORT调换后启动另一个进程,即可测试。 test7:解决相同角色,分工不同: (1)连接建立时传角色,同一个角色,多个Client,连接时间区分Client (2)连接建立时传角色和功能ID,功能ID配置到启动参数,发消息时消息头传角色和消息ID (3)细化角色。 (4)Client发送功能ID,根据功能ID、Client_ID映射文件得到Client_ID,Client_ID配置到启动参数。 (5)连接失去时,更新角色和Session的Map。 test3.type1对应test3(1) test3.type2对应test3(2) 待做: Server不能通过控制台广播到每一个Client,ioSession.write(scanner.next());之后的代码行,会等下一次控制台输入,Enter按下后执行。 test4(2)(3)、test6、test7 已经转去Vert.x了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值