文档章节

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

刺猬一号
 刺猬一号
发布于 2017/03/28 11:02
字数 1353
阅读 51
收藏 1

1、前言

Apache MINA是Apache组织的一个优秀的项目。MINA是Multipurpose Infrastructure for NetworkApplications的缩写。它是一个网络应用程序框架,用来帮助用户非常方便地开发高性能和高可靠性的网络应用程序。在本文中介绍了如何通过Apache Mina2.0来实现TCP协议长连接和短连接应用。

2、系统介绍

2.1系统框架

整个系统由两个服务端程序和两个客户端程序组成。分别实现TCP长连接和短连接通信。

系统业务逻辑是一个客户端与服务端建立长连接,一个客户端与服务端建立短连接。数据从短连接客户端经过服务端发送到长连接客户端,并从长连接客户端接收响应数据。当收到响应数据后断开连接。

系统架构图如下:

2.2处理流程

系统处理流程如下:

1)       启动服务端程序,监听8001和8002端口。

2)       长连接客户端向服务端8002端口建立连接,服务端将连接对象保存到共享内存中。由于采用长连接方式,连接对象是唯一的。

3)       短连接客户端向服务端8001端口建立连接。建立连接后创建一个连接对象。

4)       短连接客户端连接成功后发送数据。服务端接收到数据后从共享内存中得到长连接方式的连接对象,使用此对象向长连接客户端发送数据。发送前将短连接对象设为长连接对象的属性值。

5)       长连接客户端接收到数据后返回响应数据。服务端从长连接对象的属性中取得短连接对象,通过此对象将响应数据发送给短连接客户端。

6)       短连接客户端收到响应数据后,关闭连接。

3、服务端程序

3.1长连接服务端

服务启动

public class MinaLongConnServer {

private static final int PORT = 8002;

   

    public void start()throws IOException{

       IoAcceptor acceptor = new NioSocketAcceptor();

 

       acceptor.getFilterChain().addLast("logger", new LoggingFilter());

       acceptor.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

 

       acceptor.setHandler(new MinaLongConnServerHandler());

       acceptor.getSessionConfig().setReadBufferSize(2048);

       acceptor.bind(new InetSocketAddress(PORT));

       System.out.println("Listeningon port " + PORT);

    }

}

消息处理

public class MinaLongConnServerHandler extends IoHandlerAdapter {

    private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());

 

    @Override

    public void sessionOpened(IoSession session) {

       InetSocketAddress remoteAddress = (InetSocketAddress)session.getRemoteAddress();

       String clientIp = remoteAddress.getAddress().getHostAddress();

       logger.info("LongConnect Server opened Session ID ="+String.valueOf(session.getId()));

       logger.info("接收来自客户端 :" + clientIp + "的连接.");

       Initialization init = Initialization.getInstance();

       HashMap<String, IoSession> clientMap =init.getClientMap();

       clientMap.put(clientIp, session);

    }

 

    @Override

    public void messageReceived(IoSession session, Object message) {

       logger.info("Messagereceived in the long connect server..");

       String expression = message.toString();

       logger.info("Message is:" + expression);

       IoSession shortConnSession =(IoSession) session.getAttribute("shortConnSession");

       logger.info("ShortConnect Server Session ID ="+String.valueOf(shortConnSession.getId()));

       shortConnSession.write(expression);

    }

 

    @Override

    public void sessionIdle(IoSession session, IdleStatus status) {

       logger.info("Disconnectingthe idle.");

       // disconnect an idle client

       session.close(true);

    }

 

    @Override

    public void exceptionCaught(IoSession session, Throwable cause) {

       // close the connection onexceptional situation

       logger.warn(cause.getMessage(), cause);

       session.close(true);

    }

}

3.2短连接服务端

服务启动

public class MinaShortConnServer {

    private static final int PORT = 8001;

   

    public void start()throws IOException{

       IoAcceptor acceptor = new NioSocketAcceptor();

 

       acceptor.getFilterChain().addLast("logger", new LoggingFilter());

       acceptor.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

 

       acceptor.setHandler(new MinaShortConnServerHandler());

       acceptor.getSessionConfig().setReadBufferSize(2048);

       acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 3);

       acceptor.bind(new InetSocketAddress(PORT));

       System.out.println("Listeningon port " + PORT);

    }

}

消息处理

public class MinaShortConnServerHandler extends IoHandlerAdapter {

    private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());

 

    @Override

    public void sessionOpened(IoSession session) {

       InetSocketAddress remoteAddress = (InetSocketAddress)session.getRemoteAddress();

       logger.info(remoteAddress.getAddress().getHostAddress());

       logger.info(String.valueOf(session.getId()));

    }

 

    @Override

    public void messageReceived(IoSession session, Object message) {

       logger.info("Messagereceived in the short connect server...");

       String expression = message.toString();

       Initialization init = Initialization.getInstance();

       HashMap<String, IoSession> clientMap =init.getClientMap();

       if (clientMap == null || clientMap.size() == 0) {

           session.write("error");

       } else {

           IoSession longConnSession = null;

           Iterator<String> iterator =clientMap.keySet().iterator();

           String key = "";

           while (iterator.hasNext()) {

              key = iterator.next();

              longConnSession = clientMap.get(key);

           }

           logger.info("ShortConnect Server Session ID :"+String.valueOf(session.getId()));

           logger.info("LongConnect Server Session ID :"+String.valueOf(longConnSession.getId()));

           longConnSession.setAttribute("shortConnSession",session);

           longConnSession.write(expression);

       }

    }

 

    @Override

    public void sessionIdle(IoSession session, IdleStatus status) {

       logger.info("Disconnectingthe idle.");

       // disconnect an idle client

       session.close(true);

    }

 

    @Override

    public void exceptionCaught(IoSession session, Throwable cause) {

       // close the connection onexceptional situation

       logger.warn(cause.getMessage(), cause);

       session.close(true);

    }

}

 

4、客户端程序

4.1长连接客户端

使用Java.NET.Socket来实现向服务端建立连接。Socket建立后一直保持连接,从服务端接收到数据包后直接将原文返回。

public class TcpKeepAliveClient {

    private String ip;

    private int port;

    private static Socket socket = null;

    private static int timeout = 50 * 1000;

 

    public TcpKeepAliveClient(String ip, int port) {

       this.ip = ip;

       this.port = port;

    }

 

    public void receiveAndSend() throws IOException {

       InputStream input = null;

       OutputStream output = null;

 

       try {

           if (socket == null ||socket.isClosed() || !socket.isConnected()) {

              socket = new Socket();

              InetSocketAddress addr = new InetSocketAddress(ip, port);

              socket.connect(addr, timeout);

              socket.setSoTimeout(timeout);

              System.out.println("TcpKeepAliveClientnew ");

           }

 

           input = socket.getInputStream();

           output = socket.getOutputStream();

 

           // read body

           byte[] receiveBytes = {};// 收到的包字节数组

           while (true) {

              if (input.available() > 0) {

                  receiveBytes = new byte[input.available()];

                  input.read(receiveBytes);

 

                  // send

                  System.out.println("TcpKeepAliveClientsend date :" +new String(receiveBytes));

                  output.write(receiveBytes, 0, receiveBytes.length);

                  output.flush();

              }

           }

 

       } catch (Exception e) {

           e.printStackTrace();

           System.out.println("TcpClientnew socket error");

       }

    }

 

    public static void main(String[] args) throws Exception {

       TcpKeepAliveClient client = new TcpKeepAliveClient("127.0.0.1", 8002);

       client.receiveAndSend();

    }

 

}

4.2短连接客户端

服务启动

public class MinaShortClient {

    private static final int PORT = 8001;

 

    public static void main(String[] args) throws IOException,InterruptedException {

       IoConnector connector = new NioSocketConnector();

       connector.getSessionConfig().setReadBufferSize(2048);

 

       connector.getFilterChain().addLast("logger", new LoggingFilter());

       connector.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

 

       connector.setHandler(new MinaShortClientHandler());

       for (int i = 1; i <= 10; i++) {

           ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1",PORT));

           future.awaitUninterruptibly();

           IoSession session =future.getSession();

           session.write(i);

           session.getCloseFuture().awaitUninterruptibly();

 

           System.out.println("result=" + session.getAttribute("result"));

       }

       connector.dispose();

 

    }

}

消息处理

public class MinaShortClientHandler extends IoHandlerAdapter{

    private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());

 

    public MinaShortClientHandler() {

      

    }

 

    @Override

    public void sessionOpened(IoSession session) {

    }

 

    @Override

    public void messageReceived(IoSession session, Object message) {

       logger.info("Messagereceived in the client..");

       logger.info("Message is:" + message.toString());

       session.setAttribute("result", message.toString());

       session.close(true);

    }

 

    @Override

    public void exceptionCaught(IoSession session, Throwable cause) {

       session.close(true);

    }

}

5、总结

通过本文中的例子,Apache Mina在服务端可实现TCP协议长连接和短连接。在客户端只实现了短连接模式,长连接模式也是可以实现的(在本文中还是采用传统的Java Socket方式)。两个服务端之间通过共享内存的方式来传递连接对象也许有更好的实现方式。

 

工程下载地址: http://download.csdn.net/detail/peterwanghao/5306972

© 著作权归作者所有

刺猬一号
粉丝 12
博文 373
码字总数 616361
作品 0
深圳
私信 提问
关于HTTP的长连接和短连接那些事

首先这里简单提及一下HTTP协议,HTTP协议是位于应用层面向对象的协议,现在WWW中使用的是HTTP/1.1版本,关于HTTP/1.0也是今天要说的内容。 HTTP1.1比特HTTP1.0相比而言,最大的区别就是增加了...

暮回_梓
2018/06/26
0
0
TCP/IP,http,socket,长连接,短连接

TCP/IP TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传输层中有TCP协议与UDP协议。 在应用层有:TCP包括FTP...

ksfzhaohui
2012/12/14
15.6K
3
http和socket之长连接和短连接区别

TCP/IP TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传输层中有TCP协议与UDP协议。 在应用层有:TCP包括FTP...

SibylY
2015/11/06
1K
1
webSocket(二) 短轮询、长轮询、Websocket、sse

简介 Web Sockets定义了一种在通过一个单一的 socket 在网络上进行全双工通讯的通道。仅仅是传统的 HTTP 通讯的一个增量的提高,尤其对于实时、事件驱动的应用来说是一个飞跃。 通过Polling...

asyncnode
09/29
0
0
简单谈谈服务间的连接

最近又把RPC框架的底层协议翻出来回顾了一遍,梳理一下有什么可以学习和借鉴的地方,重点看了一下RPC连接的实现方案。看了之后,觉得可以谈谈服务间连接的方式及区别,所以按照自己的理解写了...

谢东升Forest
2017/07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java FOR-EACH循环

FOR-EACH循环使得代码更加的简短,也让代码更加易懂,其实他并没有加入什么新的功能。他的功能完全可以用简单的FOR循环代替。 for-each的用法: int a[] = {1,2,3,4,5,6} for(int s:a){ Syst...

无名氏的程序员
26分钟前
3
0
使用HTML5的History API

本文转载于:专业的前端网站➣使用HTML5的History API   HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL。这个功能很有用,例如通过一段JavaScript代...

前端老手
28分钟前
4
0
JAVA 编写redisUtils工具类,防止高并发获取缓存出现并发问题

import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.core.BoundHashOperations;import org.springframework.data.redis.core.BoundValueOperations;import org.......

huangkejie
今天
7
0
JMM内存模型(一)&volatile关键字的可见性

在说这个之前,我想先说一下计算机的内存模型: CPU在执行的时候,肯定要有数据,而数据在内存中放着呢,这里的内存就是计算机的物理内存,刚开始还好,但是随着技术的发展,CPU处理的速度越...

走向人生巅峰的大路
今天
100
0
你对AJAX认知有多少(2)?

接着昨日内容,我们几天继续探讨ajax的相关知识点 提到ajax下面几个问题又是必须要了解的啦~~~ 8、在浏览器端如何得到服务器端响应的XML数据。 通过XMLHttpRequest对象的responseXMl属性 9、 ...

理性思考
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部