网络编程的一些知识点
- 首先需要知道网络的几层架构,有好几种分类方式,如五层架构:物理层、数据链路层、网络层、传输层、应用层。其中IP是网络层协议,IP协议用于在互联网中找到对应的主机,TCP和UDP是传输层协议,应用层协议就很多了,最常用的就是HTTP协议。 
 
- 了解整个网络的过程是怎么样的很重要,以后学到的才可以一一对应进去。 
 
- 然后一些相关概念要掌握:ip、端口、协议、服务器、Socket(客户端、服务端等)、线程、阻塞、非阻塞、长连接、短连接、心跳机制(用于维持长连接的技术)、RPC(远程过程调用)、还有许多相关的协议。 
 
一些注意的点:
- TCP是传输层协议,主要用于建立连接。我们常说的Socket连接、Http连接等其实指的就是TCP连接。
 
- 网络是语言无关的,所以可以用两种不同的语言实现TCP连接,然后进行通信。
 
- 长连接和短连接是相对的:但都是TCP连接
 
- 对于HTTP协议,它是基于TCP/IP协议的。HTTP连接指的是TCP连接,TCP建立连接后,HTTP可以在这条连接上发出请求, 还有接受响应。因此HTTP连接叫做Http请求和Http响应更为合适。
 
- HTTP1.0默认是短连接,即完成一次网络请求就断开连接(发出HTTP请求并且接受到响应的过程)。
 
- HTTP1.1可以长连接,即客户端和服务端都不调用close方法。
 
- UDP是无连接、不可靠的。不可靠是相对的:不保证传输的到,不保证按顺序到达,不保证错误重发等。不过可以通过代码控制来保证。
 
Mina入门
Mina是什么?
Apache Mina是一个网络通信应用框架,实现了java NIO(非阻塞)技术,支持多种协议,能够帮助我们快速进行网络开发。 
除了mina框架外,还有netty框架。
为什么要有Mina?
TCP和UDP较为高深。Socket对TCP和UDP的接口进行了封装,方便程序员使用,程序员可以通过socket 创建服务端和客户端,建立连接,进行通信。
但是使用Socket会有很多线程还有并发的问题需要解决(可以使用线程池,异步IO等方法),java NIO技术就是为了解决这些而提出的一套方案。
但是java NIO编程也很复杂,因此开发出了Mina框架,让我们能够快速的进行网络编程,而不用自己去实现一套NIO方案。Mina除了实现底层IO操作外,还支持多种协议的通信,总之是十分强大的一套框架。
在Mina之上还有一些第三方平台可以实现网络通讯功能,如融云等,当然借助第三方平台也受限于第三方平台。简单的项目用第三方平台是完全没问题的。
Mina工作流程?

IoService:封装了IO操作,我们只需要使用即可,不需要自己实现异步和线程
 1 2 3
   | IoAcceptor和IoConnector都实现了IoService接口,其中 	IoAcceptor创建服务端口,用于接受连接 	IoConnector创建与服务端的连接
   | 
 
IoFilterChain:过滤器/拦截器,对数据进行过滤或拦截,Mina自带许多封装好的过滤器,当然我们也可以自己实现
 
IoHandler:提供回调方法,我们只需要在里面实现业务逻辑。
 
流程如图所示,因此我们编写代码也是按这个步骤。客户端和服务端代码基本相同,步骤如下:
- 首先创建IoService
 
- 添加过滤器/拦截器IoFilterChain
 
- 实现IoHandler对数据进行业务逻辑处理
 
怎么用Mina?
首先去官网下载mina包,导入这两个包(必须),Mina还有很多其他的包和功能,在这里就不介绍了,其实我也不会。 
Binaries是jar包,Sources是源码

编写服务端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | public class MinaServer {     public static void main(String[] args) {         try {                          NioSocketAcceptor acceptor = new NioSocketAcceptor();                          acceptor.setHandler(new MinaServerHandler());                                       acceptor.getFilterChain().addLast("log", new LoggingFilter());                          acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory()));                         
              acceptor.getSessionConfig().setReadBufferSize(2048);             
 
 
              acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);                          acceptor.bind(new InetSocketAddress(2001));         } catch (IOException e) {             e.printStackTrace();         }     } }
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   | public class MinaServerHandler extends IoHandlerAdapter {          @Override     public void exceptionCaught(IoSession session, Throwable cause) throws Exception {         System.out.println("服务端捕捉:" + cause);     }          @Override     public void messageReceived(IoSession session, Object message) throws Exception {         System.out.println("服务端消息接收:" + message.toString());                  if (message.toString().trim().equalsIgnoreCase("quit")) {             session.closeNow();             return;         }                  session.write("回复消息:" + message);     }          @Override     public void messageSent(IoSession session, Object message) throws Exception {         System.out.println("服务端消息发送:" + message.toString());     }          @Override     public void sessionClosed(IoSession session) throws Exception {         System.out.println("服务端session关闭");     }          @Override     public void sessionCreated(IoSession session) throws Exception {         System.out.println("服务端session创建");     }          @Override     public void sessionIdle(IoSession session, IdleStatus status) throws Exception {         System.out.println("服务端session闲置");     }
           @Override     public void sessionOpened(IoSession session) throws Exception {         System.out.println("服务端连接成功");     } }
  | 
 
编写客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | public class MinaClient {     public static void main(String[] args) {                  NioSocketConnector connecter = new NioSocketConnector();                  connecter.setHandler(new MinaClientHandler());                  connecter.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory()));                  ConnectFuture future = connecter.connect(new InetSocketAddress("127.0.0.1", 2001));                  future.awaitUninterruptibly();                  BufferedReader inputReader = null;         try {             inputReader = new BufferedReader(new InputStreamReader(System.in, "utf-8"));              String s;             while (!(s = inputReader.readLine()).equals("exit")) {                 future.getSession().write("客户端发送消息:" + s);             }         } catch (IOException e) {             e.printStackTrace();         }     } }
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | public class MinaClientHandler extends IoHandlerAdapter {     @Override     public void exceptionCaught(IoSession session, Throwable cause) throws Exception {         System.out.println("客户端异常捕捉");     }
      @Override     public void messageSent(IoSession session, Object message) throws Exception {         System.out.println("客户端消息发送:" + message.toString());     }
      @Override     public void sessionClosed(IoSession session) throws Exception {         System.out.println("客户端session关闭");     }
      @Override     public void sessionIdle(IoSession session, IdleStatus status) throws Exception {         System.out.println("客户端session闲置");     }
      @Override     public void sessionOpened(IoSession session) throws Exception {         System.out.println("客户端连接成功");     }
      @Override     public void messageReceived(IoSession session, Object message) throws Exception {         System.out.println("客户端接收消息:" + message.toString());
      } }
  | 
 
好了,总共只要4个类就可实现简单的异步IO通讯,将客户端和服务端代码分别运行(先运行服务端,否则客户端可能会找不到端口),然后可以从客户端控制台输入,查看输出,理解各方法的调用时机。 
补充:看到Mina中的XXXFuture就说明这个方法是异步执行的
客户端的future.awaitUninterruptibly();相当于把异步执行转变为同步执行,因此在这个方法下面的其他语句是没法执行的。这是为了防止使用future.getSession();等方法时无法返回对象的情况
可以用下面的方法代替上面的阻塞方法,这个方法用于添加监听器,在异步执行结果返回时调用监听器中的回调方法,这个方法下面的语句是能正常执行的。future.getSession();的获取可以写在回调方法里。
1 2 3 4 5
   | future.addListener(new IoFutureListener<IoFuture>() {   @Override   public void operationComplete(IoFuture ioFuture) {   } });
  | 
 
这里有一篇mina详解,讲的比较详细,有兴趣的朋友可以看这篇文章:mina框架详解
总结
第一次写博客,表达可能不是很到位,排版和字体大小应该也有问题,希望大家多多担待和支持。
下一篇将介绍如何用mina框架进行心跳检测。
以上是我自己的一些理解,如有谬误,恳请各位前辈指出!