Java NIO 与 Nio Socket

Java NIO 目录:

  1. Java NIO概述
  2. Java NIO Channel
  3. Java NIO Buffer
  4. Java NIO Scatter / Gather
  5. Java NIO 通道之间的数据传输
  6. Java NIO Selector
  7. Java NIO FileChannel
  8. Java NIO SocketChannel
  9. Java NIO ServerSocketChannel
  10. Java NIO DataGramChannel
  11. Java NIO Pipe
  12. Java NIO 与IO


[html]  view plain  copy
 print ?
  1. package com.xy.nio;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.ServerSocketChannel;  
  8. import java.util.Iterator;  
  9.   
  10. public class TCPServer {  
  11.     // 缓冲区大小  
  12.     private static final int BufferSize = 1024;  
  13.     // 超时时间,单位毫秒  
  14.     private static final int TimeOut = 3000;  
  15.     // 本地监听端口  
  16.     private static final int ListenPort = 1978;  
  17.     public static void main(String[] args) throws IOException {  
  18.         // 创建选择器  
  19.         Selector selector = Selector.open();  
  20.         // 打开监听信道  
  21.         ServerSocketChannel listenerChannel = ServerSocketChannel.open();  
  22.         // 与本地端口绑定  
  23.         listenerChannel.socket().bind(new InetSocketAddress(ListenPort));  
  24.         // 设置为非阻塞模式  
  25.         listenerChannel.configureBlocking(false);  
  26.         // 将选择器绑定到监听信道,只有非阻塞信道才可以注册选择器.并在注册过程中指出该信道可以进行Accept操作  
  27.         listenerChannel.register(selector, SelectionKey.OP_ACCEPT);  
  28.         // 创建一个处理协议的实现类,由它来具体操作  
  29.         TCPProtocol protocol = new TCPProtocolImpl(BufferSize);  
  30.   
  31.         // 反复循环,等待IO  
  32.         while (true) {  
  33.             // 等待某信道就绪(或超时)  
  34.             if (selector.select(TimeOut) == 0) {// 监听注册通道,当其中有注册的 IO  
  35.                                                 // 操作可以进行时,该函数返回,并将对应的  
  36.                                                 // SelectionKey 加入 selected-key  
  37.                                                 // set  
  38.                 System.out.print("独自等待.");  
  39.                 continue;  
  40.             }  
  41.             // 取得迭代器.selectedKeys()中包含了每个准备好某一I/O操作的信道的SelectionKey  
  42.             // Selected-key Iterator 代表了所有通过 select() 方法监测到可以进行 IO 操作的 channel  
  43.             // ,这个集合可以通过 selectedKeys() 拿到  
  44.             Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();  
  45.             while (keyIter.hasNext()) {  
  46.                 SelectionKey key = keyIter.next();  
  47.                 SelectionKey key1;  
  48.                 if (keyIter.hasNext()) {  
  49.                     key1 = keyIter.next();  
  50.                 }  
  51.                 try {  
  52.                     if (key.isAcceptable()) {  
  53.                         // 有客户端连接请求时  
  54.                         protocol.handleAccept(key);  
  55.                     }  
  56.                     if (key.isReadable()) {// 判断是否有数据发送过来  
  57.                         // 从客户端读取数据  
  58.                         protocol.handleRead(key);  
  59.                     }  
  60.                     if (key.isValid() && key.isWritable()) {// 判断是否有效及可以发送给客户端  
  61.                         // 客户端可写时  
  62.                         protocol.handleWrite(key);  
  63.                     }  
  64.                 } catch (IOException ex) {  
  65.                     // 出现IO异常(如客户端断开连接)时移除处理过的键  
  66.                     keyIter.remove();  
  67.                     continue;  
  68.                 }  
  69.                 // 移除处理过的键  
  70.                 keyIter.remove();  
  71.             }  
  72.         }  
  73.     }  
  74. }  


TCPProtocol.java读写处理接口

[html]  view plain  copy
 print ?
  1. package com.xy.nio;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.channels.SelectionKey;  
  5.   
  6. public interface TCPProtocol{  
  7.    /**  
  8.     * 接收一个SocketChannel的处理  
  9.     * @param key  
  10.     * @throws IOException  
  11.     */  
  12.    void handleAccept(SelectionKey key) throws IOException;  
  13.      
  14.    /**  
  15.     * 从一个SocketChannel读取信息的处理  
  16.     * @param key  
  17.     * @throws IOException  
  18.     */  
  19.    void handleRead(SelectionKey key) throws IOException;  
  20.      
  21.    /**  
  22.     * 向一个SocketChannel写入信息的处理  
  23.     * @param key  
  24.     * @throws IOException  
  25.     */  
  26.    void handleWrite(SelectionKey key) throws IOException;  
  27.  }  

TCPProtocolImpl.java接口实现

[html]  view plain  copy
 print ?
  1. package com.xy.nio;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.ServerSocketChannel;  
  7. import java.nio.channels.SocketChannel;  
  8. import java.nio.charset.Charset;  
  9. import java.util.Date;  
  10.   
  11. public class TCPProtocolImpl implements TCPProtocol {  
  12.     private int bufferSize;  
  13.   
  14.     public TCPProtocolImpl(int bufferSize) {  
  15.         this.bufferSize = bufferSize;  
  16.     }  
  17.   
  18.     public void handleAccept(SelectionKey key) throws IOException {  
  19.         // 返回创建此键的通道,接受客户端建立连接的请求,并返回 SocketChannel 对象  
  20.         SocketChannel clientChannel = ((ServerSocketChannel) key.channel())  
  21.                 .accept();  
  22.         // 非阻塞式  
  23.         clientChannel.configureBlocking(false);  
  24.         // 注册到selector  
  25.         clientChannel.register(key.selector(), SelectionKey.OP_READ,  
  26.                 ByteBuffer.allocate(bufferSize));  
  27.     }  
  28.   
  29.     public void handleRead(SelectionKey key) throws IOException {  
  30.         // 获得与客户端通信的信道  
  31.         SocketChannel clientChannel = (SocketChannel) key.channel();  
  32.         // 得到并清空缓冲区  
  33.         ByteBuffer buffer = (ByteBuffer) key.attachment();  
  34.         buffer.clear();  
  35.         // 读取信息获得读取的字节数  
  36.         long bytesRead = clientChannel.read(buffer);  
  37.         if (bytesRead == -1) {  
  38.             // 没有读取到内容的情况  
  39.             clientChannel.close();  
  40.         } else {  
  41.             // 将缓冲区准备为数据传出状态  
  42.             buffer.flip();  
  43.             // 将字节转化为为UTF-16的字符串  
  44.             String receivedString = Charset.forName("UTF-16").newDecoder()  
  45.                     .decode(buffer).toString();  
  46.             // 控制台打印出来  
  47.             System.out.println("接收到来自"  
  48.                     + clientChannel.socket().getRemoteSocketAddress() + "的信息:"  
  49.                     + receivedString);  
  50.             // 准备发送的文本  
  51.             String sendString = "你好,客户端. @" + new Date().toString()  
  52.                     + ",已经收到你的信息" + receivedString;  
  53.             buffer = ByteBuffer.wrap(sendString.getBytes("UTF-16"));  
  54.             clientChannel.write(buffer);  
  55.             // 设置为下一次读取或是写入做准备  
  56.             key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);  
  57.         }  
  58.     }  
  59.   
  60.     public void handleWrite(SelectionKey key) throws IOException {  
  61.         // do nothing  
  62.     }  
  63. }  
TCPClientReadThread.java客户端:

[html]  view plain  copy
 print ?
  1. package com.xy.nio;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.SocketChannel;  
  8. import java.nio.charset.Charset;  
  9.   
  10. public class TCPClientReadThread implements Runnable {  
  11.     private Selector selector;  
  12.   
  13.     public TCPClientReadThread(Selector selector) {  
  14.         this.selector = selector;  
  15.   
  16.         new Thread(this).start();  
  17.     }  
  18.   
  19.     @SuppressWarnings("static-access")  
  20.     public void run() {  
  21.         try {  
  22.             while (selector.select() > 0) {//select()方法只能使用一次,用了之后就会自动删除,每个连接到服务器的选择器都是独立的  
  23.                 // 遍历每个有可用IO操作Channel对应的SelectionKey  
  24.                 for (SelectionKey sk : selector.selectedKeys()) {  
  25.                     // 如果该SelectionKey对应的Channel中有可读的数据  
  26.                     if (sk.isReadable()) {  
  27.                         // 使用NIO读取Channel中的数据  
  28.                         SocketChannel sc = (SocketChannel) sk.channel();//获取通道信息  
  29.                         ByteBuffer buffer = ByteBuffer.allocate(1024);//分配缓冲区大小  
  30.                         sc.read(buffer);//读取通道里面的数据放在缓冲区内  
  31.                         buffer.flip();// 调用此方法为一系列通道写入或相对获取 操作做好准备  
  32.                         // 将字节转化为为UTF-16的字符串  
  33.                         String receivedString = Charset.forName("UTF-16")  
  34.                                 .newDecoder().decode(buffer).toString();  
  35.                         // 控制台打印出来  
  36.                         System.out.println("接收到来自服务器"  
  37.                                 + sc.socket().getRemoteSocketAddress() + "的信息:"  
  38.                                 + receivedString);  
  39.                         // 为下一次读取作准备  
  40.                         sk.interestOps(SelectionKey.OP_READ);  
  41.                     }  
  42.                     // 删除正在处理的SelectionKey  
  43.                     selector.selectedKeys().remove(sk);  
  44.                 }  
  45.             }  
  46.         } catch (IOException ex) {  
  47.             ex.printStackTrace();  
  48.         }  
  49.     }  
  50. }  

TCPClient.java

[html]  view plain  copy
 print ?
  1. package com.xy.nio;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.channels.SelectionKey;  
  7. import java.nio.channels.Selector;  
  8. import java.nio.channels.SocketChannel;  
  9. import java.util.Scanner;  
  10.   
  11. public class TCPClient {  
  12.     // 信道选择器  
  13.     private Selector selector;  
  14.   
  15.     // 与服务器通信的信道  
  16.     SocketChannel socketChannel;  
  17.   
  18.     // 要连接的服务器Ip地址  
  19.     private String hostIp;  
  20.   
  21.     // 要连接的远程服务器在监听的端口  
  22.     private int hostListenningPort;  
  23.   
  24.     public TCPClient(String HostIp, int HostListenningPort) throws IOException {  
  25.         this.hostIp = HostIp;  
  26.         this.hostListenningPort = HostListenningPort;  
  27.   
  28.         initialize();  
  29.     }  
  30.     /**  
  31.      * 初始化  
  32.      *   
  33.      * @throws IOException  
  34.      */  
  35.     private void initialize() throws IOException {  
  36.         // 打开监听信道并设置为非阻塞模式  
  37.         socketChannel = SocketChannel.open(new InetSocketAddress(hostIp,  
  38.                 hostListenningPort));  
  39.         socketChannel.configureBlocking(false);  
  40.   
  41.         // 打开并注册选择器到信道  
  42.         selector = Selector.open();  
  43.         socketChannel.register(selector, SelectionKey.OP_READ);  
  44.   
  45.         // 启动读取线程  
  46.         new TCPClientReadThread(selector);  
  47.     }  
  48.     /**  
  49.      * 发送字符串到服务器  
  50.      *   
  51.      * @param message  
  52.      * @throws IOException  
  53.      */  
  54.     public void sendMsg(String message) throws IOException {  
  55.         ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes("UTF-8"));  
  56.         socketChannel.write(writeBuffer);  
  57.     }  
  58.     static TCPClient client;  
  59.     static boolean mFlag = true;  
  60.     public static void main(String[] args) throws IOException {  
  61.         client = new TCPClient("10.81.36.193", 1978);  
  62.         new Thread() {  
  63.             @Override  
  64.             public void run() {  
  65.                 try {  
  66.                     client.sendMsg("你好!Nio!醉里挑灯看剑,梦回吹角连营");  
  67.                     while (mFlag) {  
  68.                         Scanner scan = new Scanner(System.in);//键盘输入数据  
  69.                         String string = scan.next();  
  70.                         client.sendMsg(string);  
  71.                     }  
  72.                 } catch (IOException e) {  
  73.                     mFlag = false;  
  74.                     e.printStackTrace();  
  75.                 } finally {  
  76.                     mFlag = false;  
  77.                 }  
  78.                 super.run();  
  79.             }  
  80.         }.start();  
  81.     }  
  82. }  


  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值