java NIO

来源:互联网 发布:手机淘宝怎么申请帐号 编辑:程序博客网 时间:2024/06/06 17:25

nio是new io的简称,从jdk1.4就被引入了。现在的jdk已经到了1.6了,可以说不是什么新东西了。但其中的一些思想值得我来研究。这两天,我研究了下其中的套接字部分,有一些心得,在此分享。 首先先分析下:为什么要nio套接字? nio的主要作用就是用来解决速度差异的。举个例子:计算机处理的速度,和用户按键盘的速度。这两者的速度相差悬殊。如果按照经典的方法:一个用户设定一个线程,专门等待用户的输入,无形中就造成了严重的资源浪费:每一个线程都需要珍贵的cpu时间片,由于速度差异造成了在这个交互线程中的cpu都用来等待。 nio套接字是怎么做到的? 其实,其中的思想很简单:轮询。一个线程轮询多个input;传统的方式是:有n个客户端就要有n个服务线程+一个监听线程,现在采取这种凡是,可以仅仅使用1个线程来代替n个服务线程以此来解决。 具体应用例子: 在ftp的控制连接中,因为只有少量的字符命令进行传输,所以可以考虑利用这种轮询的方式实现,以节省资源。 具体见例子。 Java代码
  package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }
  public IoEchoServer() throws IOException {
  ServerSocket server = new ServerSocket(1984);
  while (true) {
  Socket socket = server.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  System.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  }

 

 

 package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }
  public IoEchoServer() throws IOException {
  ServerSocket <A title=server href="http://www.google.cn/search?sbi=server&q=server&sbb=搜索&sa=搜索&client=pub-6430022987645146&forid=1&prog=aff&ie=GB2312&oe=GB2312&hl=zh-CN" target=_blank>server</A> = new ServerSocket(1984);
  while (true) {
  Socket socket = <A title=server href="http://www.google.cn/search?sbi=server&q=server&sbb=搜索&sa=搜索&client=pub-6430022987645146&forid=1&prog=aff&ie=GB2312&oe=GB2312&hl=zh-CN" target=_blank>server</A>.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  <A title=system href="http://www.alimama.com/membersvc/buyadzone/buy_ad_zone.htm?adzoneid=892989 " target=_blank>system</A>.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  }
  package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }

 

public IoEchoServer() throws IOException {
  ServerSocket server = new ServerSocket(1984);
  while (true) {
  Socket socket = server.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  system.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  } 下面这个例子采取了nio方式实现,虽然还是有阻塞部分,但是与上一个相比,效率已经大幅提高。仅仅阻塞到一个监听线程中。 Java代码
  package com.cxz.nio;
  import java.io.IOException;
  import java.net.InetSocketAddress;
  import java.nio.ByteBuffer;
  import java.nio.CharBuffer;
  import java.nio.channels.SelectionKey;
  import java.nio.channels.Selector;
  import java.nio.channels.ServerSocketChannel;
  import java.nio.channels.SocketChannel;
  import java.nio.charset.Charset;
  import java.nio.charset.CharsetDecoder;
  import java.util.Iterator;
  import java.util.Set;
  public class NioEchoServer {
  private static Selector roller = null;
  private static final int port = 8080;
  private static NioEchoServer instance = null;
  private ThreadLocal<StringBuffer> stringLocal = new ThreadLocal<StringBuffer>();
  private NioEchoServer() throws IOException {
  ServerSocketChannel serverChannel = ServerSocketChannel.open();
  serverChannel.socket().bind(new InetSocketAddress(port));
  serverChannel.configureBlocking(false);
  serverChannel.register(roller, SelectionKey.OP_ACCEPT);
  }
  public synchronized static NioEchoServer getInstance() throws IOException {
  if (instance == null) {
  roller = Selector.open();
  instance = new NioEchoServer();
  }
  return instance;
  }
  public void start() throws IOException {
  int keyAdded = 0;
  while ((keyAdded = roller.select()) > 0) {
  Set<SelectionKey> keySets = roller.selectedKeys();
  Iterator iter = keySets.iterator();
  while (iter.hasNext()) {
  SelectionKey key = (SelectionKey) iter.next();
  iter.remove();
  actionHandler(key);
  }
  }
  }

 

public void actionHandler(SelectionKey key) throws IOException {
  if (key.isAcceptable()) {
  ServerSocketChannel serverChannel = (ServerSocketChannel) key
  .channel();
  SocketChannel socketChannel = serverChannel.accept();
  socketChannel.configureBlocking(false);
  socketChannel.register(roller, SelectionKey.OP_READ);
  } else if (key.isReadable()) {
  ByteBuffer buffer = ByteBuffer.allocate(16);
  SocketChannel socketChannel = (SocketChannel) key.channel();
  socketChannel.read(buffer);
  buffer.flip();
  String temp = decode(buffer);
  StringBuffer strBuffer = stringLocal.get();
  if (strBuffer == null) {
  strBuffer = new StringBuffer();
  }
  strBuffer.append(temp);
  if (temp.equals("/r/n")) {
  System.out.println(strBuffer.toString());
  strBuffer = null;
  }
  stringLocal.set(strBuffer);
  }
  }
  public String decode(ByteBuffer buffer) {
  Charset charset = null;
  CharsetDecoder decoder = null;
  CharBuffer charBuffer = null;
  try {
  charset = Charset.forName("UTF-8");
  decoder = charset.newDecoder();
  charBuffer = decoder.decode(buffer);
  return charBuffer.toString();
  } catch (Exception ex) {
  ex.printStackTrace();
  return "";
  }
  }
  public static void main(String[] args) {
  try {
  NioEchoServer.getInstance().start();
  } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
  }
  }