NIO与传统IO的区别 NIO Socket例子 实例

传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。

小量的线程如何同时为大量连接服务呢,答案就是就绪选择。这就好比到餐厅吃饭,每来一桌客人,都有一个服务员专门为你服务,从你到餐厅到结帐走人,这样方式的好处是服务质量好,一对一的服务,VIP啊,可是缺点也很明显,成本高,如果餐厅生意好,同时来100桌客人,就需要100个服务员,那老板发工资的时候得心痛死了,这就是传统的一个连接一个线程的方式。

老板是什么人啊,精着呢。这老板就得捉摸怎么能用10个服务员同时为100桌客人服务呢,老板就发现,服务员在为客人服务的过程中并不是一直都忙着,客人点完菜,上完菜,吃着的这段时间,服务员就闲下来了,可是这个服务员还是被这桌客人占用着,不能为别的客人服务,用华为领导的话说,就是工作不饱满。那怎么把这段闲着的时间利用起来呢。这餐厅老板就想了一个办法,让一个服务员(前台)专门负责收集客人的需求,登记下来,比如有客人进来了、客人点菜了,客人要结帐了,都先记录下来按顺序排好。每个服务员到这里领一个需求,比如点菜,就拿着菜单帮客人点菜去了。点好菜以后,服务员马上回来,领取下一个需求,继续为别人客人服务去了。这种方式服务质量就不如一对一的服务了,当客人数据很多的时候可能需要等待。但好处也很明显,由于在客人正吃饭着的时候服务员不用闲着了,服务员这个时间内可以为其他客人服务了,原来10个服务员最多同时为10桌客人服务,现在可能为50桌,60客人服务了。

这种服务方式跟传统的区别有两个:
1、增加了一个角色,要有一个专门负责收集客人需求的人。NIO里对应的就是Selector。
2、由阻塞服务方式改为非阻塞服务了,客人吃着的时候服务员不用一直侯在客人旁边了。传统的IO操作,比如read(),当没有数据可读的时候,线程一直阻塞被占用,直到数据到来。NIO中没有数据可读时,read()会立即返回0,线程不会阻塞。

NIO中,客户端创建一个连接后,先要将连接注册到Selector,相当于客人进入餐厅后,告诉前台你要用餐,前台会告诉你你的桌号是几号,然后你就可能到那张桌子坐下了,SelectionKey就是桌号。当某一桌需要服务时,前台就记录哪一桌需要什么服务,比如1号桌要点菜,2号桌要结帐,服务员从前台取一条记录,根据记录提供服务,完了再来取下一条。这样服务的时间就被最有效的利用起来了。


=======================================================

NIO Socket例子 实例

服务端:

[java]  view plain  copy
  1. public class ServerSocketChannelTest {  
  2.  private static byte[] data = new byte[255];  
  3.   
  4.  public static void main(String[] args) throws IOException {  
  5.   for (int i = 0; i < data.length; i++) {  
  6.    data[i] = (byte) i;  
  7.   }  
  8.   //新建NIO通道  
  9.   ServerSocketChannel server = ServerSocketChannel.open();  
  10.   //使通道为非阻塞  
  11.   server.configureBlocking(false);  
  12.   //创建基于NIO通道的socket连接  
  13.   ServerSocket ss = server.socket();  
  14.   //新建socket通道的端口  
  15.   ss.bind(new InetSocketAddress(9000));  
  16.   //将NIO通道绑定到选择器  
  17.   Selector selector = Selector.open();  
  18.   server.register(selector, SelectionKey.OP_ACCEPT);  
  19.   
  20.   while (true) {  
  21.    //获取通道内是否有选择器的关心事件  
  22.    int num = selector.select();  
  23.    //如果小于1,停止此次循环,进行下一个循环  
  24.    if (num < 1) {  
  25.     continue;  
  26.    }  
  27.    //获取通道内关心事件的集合  
  28.    Set selectedKeys = selector.selectedKeys();  
  29.    Iterator iterator = selectedKeys.iterator();  
  30.    while (iterator.hasNext()) {  
  31.     SelectionKey key = (SelectionKey) iterator.next();  
  32.     //移走此次事件  
  33.     iterator.remove();  
  34.       
  35.     if (key.isAcceptable()) {  
  36.      //获取对应的SocketChannel  
  37.      SocketChannel client = server.accept();  
  38.      System.out.println("Accepted connection from " + client);  
  39.      //使此通道为非阻塞  
  40.      client.configureBlocking(false);  
  41.      //将数组data的大小定义为ByteBuffer缓冲区的大小  
  42.      ByteBuffer source = ByteBuffer.wrap(data);  
  43.        
  44.      //在此通道上注册事件  
  45.      SelectionKey key2 = client.register(selector,  
  46.        SelectionKey.OP_WRITE);  
  47.      //通道执行事件  
  48.      key2.attach(source);  
  49.     } else if (key.isWritable()) {  
  50.      //获取此通道的SocketChannel  
  51.      SocketChannel client = (SocketChannel) key.channel();  
  52.      ByteBuffer output = (ByteBuffer) key.attachment();  
  53.      //如果缓存区没了,重置一下  
  54.      if (!output.hasRemaining()) {  
  55.       output.rewind();  
  56.      }  
  57.      //在此通道内写东西  
  58.      client.write(output);  
  59.     }  
  60.     key.channel().close();  
  61.    }  
  62.   
  63.   }  
  64.   
  65.  }  
  66.   
  67. }  

客户端:

[java]  view plain  copy
  1. public class SocketChannelTest {  
  2.  public static void main(String[] args) throws Exception {  
  3.   //建立到服务端的链接  
  4.   SocketAddress address = new InetSocketAddress("127.0.0.1"9000);  
  5.   SocketChannel client = SocketChannel.open(address);  
  6.   //创建静态的缓冲区  
  7.   ByteBuffer buffer = ByteBuffer.allocate(255);  
  8.   
  9.   //读取数据,到buffer中  
  10.   client.read(buffer);  
  11.   //将position重新置为0  
  12.   buffer.clear();  
  13.   //输出缓冲区的数据  
  14.   for (int i = 0; i < buffer.array().length; i++) {  
  15.    System.out.println(buffer.array()[i]);  
  16.   }  
  17.  }  
  18. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值