多语言展示
当前在线:1267今日阅读:23今日分享:31

Java NIO网络编程开发入门教程

java.nio(non-blocking IO)是Java 1.4新增的特性,Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持。这里介绍如何使用Java NIO的框架构建高性能网络服务应用
工具/原料
1

Java 1.8

2

Eclipse

方法/步骤
1

Java NIO的核心组件包含Channels,buffers,Selectors三个核心的组件,将Java NIO的网络编程模型总结如下图所示

2

构建网络应用服务端:EchoServer.javapackage hxb.echo;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class EchoServer { private Selector selector =null; public EchoServer(){ } /** * 写消息到客户端 */    private void doWrite(SocketChannel channel,String response) throws IOException{          byte[] bytes = response.getBytes();          ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);          writeBuffer.put(bytes);          writeBuffer.flip();          channel.write(writeBuffer);      }    /**     * 处理客户端信息     */ private void handleForReadKey(SelectionKey key) throws IOException, UnsupportedEncodingException { SocketChannel sc = (SocketChannel) key.channel();   ByteBuffer buffer = ByteBuffer.allocate(1024);   int readBytes = sc.read(buffer);   if(readBytes>0){      buffer.flip();      byte[] bytes = new byte[buffer.remaining()];      buffer.get(bytes);      String msg = new String(bytes);      System.out.println('Message send by Client:' + msg);      //响应消息      String rspMsg = 'Send by Server:'+msg;      doWrite(sc,rspMsg);   }   else if(readBytes<0){      key.cancel();      sc.close();   } }   /** * 启动服务器 * @param port 服务器端口 */ public void start(int port) { ServerSocketChannel serverChannel = null; try {     selector = Selector.open(); serverChannel = ServerSocketChannel.open();   serverChannel.configureBlocking(false);//配置为非阻塞模式 SocketAddress addr = new InetSocketAddress(port); serverChannel.bind(addr ); System.out.println('Start Echo server and listen on the port '+port); //监听 serverChannel.register(selector, SelectionKey.OP_ACCEPT);   while(true) { //必须:唤醒selector selector.select();     Set keys = selector.selectedKeys(); Iterator iterator = keys.iterator(); SelectionKey key = null; while(iterator.hasNext()) { key=iterator.next(); iterator.remove(); handle(key); } }   } catch (IOException e) { e.printStackTrace(); } finally { if(serverChannel!=null) { try { serverChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 处理消息事件 * @param key */ private void handle(SelectionKey key) { if(key.isValid()) { if(key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); try { SocketChannel ss = ssc.accept(); ss.configureBlocking(false); //Selection 从Accept 切换到read数据 ss.register(selector, SelectionKey.OP_READ); } catch (IOException e) { e.printStackTrace(); } } else if(key.isReadable()) { try { handleForReadKey(key); } catch (IOException e) { e.printStackTrace(); }  } } } public static void main(String[] args) { EchoServer server = new EchoServer(); server.start(9527); }}

3

构建网络服务客户端处理线程:ClientHandle.javapackage hxb.echo;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class ClientHandle implements Runnable{      private String host;      private int port;      private Selector selector;      private SocketChannel socketChannel;      private volatile boolean started;        public ClientHandle(String ip,int port) {          this.host = ip;          this.port = port;          try{              selector = Selector.open();              socketChannel = SocketChannel.open();              socketChannel.configureBlocking(false);//开启非阻塞模式              started = true;          }catch(IOException e){              e.printStackTrace();              System.exit(1);          }      }      public void stop(){          started = false;      }      @Override      public void run() {          try{              doConnect();          }catch(IOException e){              e.printStackTrace();              System.exit(1);          }          while(started){              try{                  selector.select();                  Set keys = selector.selectedKeys();                  Iterator it = keys.iterator();                  SelectionKey key = null;                  while(it.hasNext()){                      key = it.next();                      it.remove();                      try{                          handleInput(key);                      }catch(Exception e){                          if(key != null){                              key.cancel();                              if(key.channel() != null){                                  key.channel().close();                              }                          }                      }                  }              }catch(Exception e){                  e.printStackTrace();                  System.exit(1);              }          }          if(selector != null)              try{                  selector.close();              }catch (Exception e) {                  e.printStackTrace();              }      }      private void handleInput(SelectionKey key) throws IOException{          if(key.isValid()){              SocketChannel sc = (SocketChannel) key.channel();              if(key.isConnectable()){                  if(sc.finishConnect());                  else System.exit(1);              }              //读消息              if(key.isReadable()){                  ByteBuffer buffer = ByteBuffer.allocate(1024);                  int readBytes = sc.read(buffer);                  if(readBytes>0){                      buffer.flip();                      byte[] bytes = new byte[buffer.remaining()];                      buffer.get(bytes);                      String result = new String(bytes,'UTF-8');                      System.out.println('客户端收到消息:' + result);                  }                  else if(readBytes<0){                      key.cancel();                      sc.close();                  }              }          }      }      //异步发送消息      private void doWrite(SocketChannel channel,String request) throws IOException{          byte[] bytes = request.getBytes();          ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);          writeBuffer.put(bytes);          writeBuffer.flip();          channel.write(writeBuffer);      }      private void doConnect() throws IOException{          if(socketChannel.connect(new InetSocketAddress(host,port)));          else socketChannel.register(selector, SelectionKey.OP_CONNECT);      }      public void sendMsg(String msg) throws Exception{          socketChannel.register(selector, SelectionKey.OP_READ);          doWrite(socketChannel, msg);      }  }

4

构建网络应用客户端主程序Client.javapackage hxb.echo;import java.util.Scanner;public class Client {      private static String DEFAULT_HOST = '127.0.0.1';      private static int DEFAULT_PORT = 9527;      private static ClientHandle clientHandle;      public static synchronized void start(String ip,int port){          if(clientHandle!=null)              clientHandle.stop();          clientHandle = new ClientHandle(ip,port);          new Thread(clientHandle,'Server').start();      }      //向服务器发送消息      public static boolean sendMsg(String msg) throws Exception{          clientHandle.sendMsg(msg);          return true;      }      public static void main(String[] args){      Client client = new Client();    client.start(DEFAULT_HOST,DEFAULT_PORT);    try { while(Client.sendMsg(new Scanner(System.in).nextLine())); } catch (Exception e) { e.printStackTrace(); }      }  }

5

启动EchServer程序,在控制台Console会输出“”Start Echo server and listen on the port 9527“”,表明服务启动成功

6

启动Client客户端程序进行测试

推荐信息