NIO主要原理和适用

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有 事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从 这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对 每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU的处理能力和处理中的等待时间,达到提高服务能力的目的。

这段时间在研究NIO,写篇博客来记住学过的东西。还是从最简单的Hello World开始,client多线程请求server端,server接收client的名字,并返回Hello! +名字的字符格式给client。当然实际应用并不这么简单,实际可能是访问文件或者数据库获取信息返回给client。非阻塞的NIO有何神秘之处?

代 码:

1)server端代码

  1. public class HelloWorldServer {
  2. static int BLOCK = 1024;
  3. static String name = "";
  4. protected Selector selector;
  5. protected ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);
  6. protected CharsetDecoder decoder;
  7. static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
  8. public HelloWorldServer(int port) throws IOException {
  9. selector = this.getSelector(port);
  10. Charset charset = Charset.forName("GB2312");
  11. decoder = charset.newDecoder();
  12. }
  13. // 获取Selector
  14. protected Selector getSelector(int port) throws IOException {
  15. ServerSocketChannel server = ServerSocketChannel.open();
  16. Selector sel = Selector.open();
  17. server.socket().bind(new InetSocketAddress(port));
  18. server.configureBlocking(false);
  19. server.register(sel, SelectionKey.OP_ACCEPT);
  20. return sel;
  21. }
  22. // 监听端口
  23. public void listen() {
  24. try {
  25. for (;;) {
  26. selector.select();
  27. Iterator iter = selector.selectedKeys().iterator();
  28. while (iter.hasNext()) {
  29. SelectionKey key = (SelectionKey) iter.next();
  30. iter.remove();
  31. process(key);
  32. }
  33. }
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. // 处理事件
  39. protected void process(SelectionKey key) throws IOException {
  40. if (key.isAcceptable()) { // 接收请求
  41. ServerSocketChannel server = (ServerSocketChannel) key.channel();
  42. SocketChannel channel = server.accept();
  43. //设置非阻塞模式
  44. channel.configureBlocking(false);
  45. channel.register(selector, SelectionKey.OP_READ);
  46. } else if (key.isReadable()) { // 读信息
  47. SocketChannel channel = (SocketChannel) key.channel();
  48. int count = channel.read(clientBuffer);
  49. if (count > 0) {
  50. clientBuffer.flip();
  51. CharBuffer charBuffer = decoder.decode(clientBuffer);
  52. name = charBuffer.toString();
  53. // System.out.println(name);
  54. SelectionKey sKey = channel.register(selector,
  55. SelectionKey.OP_WRITE);
  56. sKey.attach(name);
  57. } else {
  58. channel.close();
  59. }
  60. clientBuffer.clear();
  61. } else if (key.isWritable()) { // 写事件
  62. SocketChannel channel = (SocketChannel) key.channel();
  63. String name = (String) key.attachment();
  64. ByteBuffer block = encoder.encode(CharBuffer
  65. .wrap("Hello !" + name));
  66. channel.write(block);
  67. //channel.close();
  68. }
  69. }
  70. public static void main(String[] args) {
  71. int port = 8888;
  72. try {
  73. HelloWorldServer server = new HelloWorldServer(port);
  74. System.out.println("listening on " + port);
  75. server.listen();
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. }

2)client端代码

  1. public class HelloWorldClient {
  2. static int SIZE = 10;
  3. static InetSocketAddress ip = new InetSocketAddress("localhost", 8888);
  4. static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
  5. static class Message implements Runnable {
  6. protected String name;
  7. String msg = "";
  8. public Message(String index) {
  9. this.name = index;
  10. }
  11. public void run() {
  12. try {
  13. long start = System.currentTimeMillis();
  14. //打开Socket通道
  15. SocketChannel client = SocketChannel.open();
  16. //设置为非阻塞模式
  17. client.configureBlocking(false);
  18. //打开选择器
  19. Selector selector = Selector.open();
  20. //注册连接服务端socket动作
  21. client.register(selector, SelectionKey.OP_CONNECT);
  22. //连接
  23. client.connect(ip);
  24. //分配内存
  25. ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
  26. int total = 0;
  27. _FOR: for (;;) {
  28. selector.select();
  29. Iterator iter = selector.selectedKeys().iterator();
  30. while (iter.hasNext()) {
  31. SelectionKey key = (SelectionKey) iter.next();
  32. iter.remove();
  33. if (key.isConnectable()) {
  34. SocketChannel channel = (SocketChannel) key
  35. .channel();
  36. if (channel.isConnectionPending())
  37. channel.finishConnect();
  38. channel
  39. .write(encoder
  40. .encode(CharBuffer.wrap(name)));
  41. channel.register(selector, SelectionKey.OP_READ);
  42. } else if (key.isReadable()) {
  43. SocketChannel channel = (SocketChannel) key
  44. .channel();
  45. int count = channel.read(buffer);
  46. if (count > 0) {
  47. total += count;
  48. buffer.flip();
  49. while (buffer.remaining() > 0) {
  50. byte b = buffer.get();
  51. msg += (char) b;
  52. }
  53. buffer.clear();
  54. } else {
  55. client.close();
  56. break _FOR;
  57. }
  58. }
  59. }
  60. }
  61. double last = (System.currentTimeMillis() - start) * 1.0 / 1000;
  62. System.out.println(msg + "used time :" + last + "s.");
  63. msg = "";
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. }
  67. }
  68. }
  69. public static void main(String[] args) throws IOException {
  70. String names[] = new String[SIZE];
  71. for (int index = 0; index < SIZE; index++) {
  72. names[index] = "jeff[" + index + "]";
  73. new Thread(new Message(names[index])).start();
  74. }
  75. }
  76. }

NIO Socket非阻塞模式的更多相关文章

  1. Java NIO Socket 非阻塞通信

    相对于非阻塞通信的复杂性,通常客户端并不需要使用非阻塞通信以提高性能,故这里只有服务端使用非阻塞通信方式实现 客户端: package com.test.client; import java.io. ...

  2. 看到关于socket非阻塞模式设置方式记录一下。

    关于socket的阻塞与非阻塞模式以及它们之间的优缺点,这已经没什么可言的:我打个很简单的比方,如果你调用socket send函数时: 如果是阻塞模式下: send先比较待发送数据的长度len和套接 ...

  3. JAVA NIO使用非阻塞模式实现高并发服务器

    参考:http://blog.csdn.net/zmx729618/article/details/51860699  https://zhuanlan.zhihu.com/p/23488863 ht ...

  4. JAVA基础知识之网络编程——-基于NIO的非阻塞Socket通信

    阻塞IO与非阻塞IO 通常情况下的Socket都是阻塞式的, 程序的输入输出都会让当前线程进入阻塞状态, 因此服务器需要为每一个客户端都创建一个线程. 从JAVA1.4开始引入了NIO API, NI ...

  5. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

  6. UDP socket 设置为的非阻塞模式

    UDP socket 设置为的非阻塞模式 Len = recvfrom(SocketFD, szRecvBuf, sizeof(szRecvBuf), MSG_DONTWAIT, (struct so ...

  7. socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto

    socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...

  8. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

  9. Socket阻塞模式和非阻塞模式的区别

    简单点说: 阻塞就是干不完不准回来,    非组赛就是你先干,我现看看有其他事没有,完了告诉我一声 我们拿最常用的send和recv两个函数来说吧... 比如你调用send函数发送一定的Byte,在系 ...

随机推荐

  1. 用CSS创建小三角形问题(笔试题常考)

    笔试题中经常遇到用CSS实现某个Div边框添加三角形问题,掌握一点,合理利用div的边框,当div有宽有高时,边框就是不起眼的边框,当div的宽高为0时,边框就是一个小方块,把剩下的三个边透明就是神奇 ...

  2. Java面试——基础

    1,作用域,Java只有public,protect,private,默认是default相当于friendly 作用域 当前类          同一package 子类            其它 ...

  3. Android中两种设置全屏或者无标题的方法

    在开发中我们经常需要把我们的应用设置为全屏或者不想要title, 这里是有两种方法的,一种是在代码中设置,另一种方法是在配置文件里改: 一.在代码中设置: package jason.tutor; i ...

  4. angularJS学习笔记二

    angularJS四个特性 1.MVC <!doctype html> <html ng-app> <head> <meta charset="ut ...

  5. git stash 保存修改现场

    用途:当你正在分支上做一个项目的时候,突然必须停下来去做别的事情,但因为没有此项目还没改好,所以不想commit 就可以保留现场,等忙完后再回复现场继续修改. bug处理保存开发现场$ git sta ...

  6. js与jquery获取父元素,删除子元素的不同方法

    var obj=document.getElementById("id");得到的是dom对象,对该对象进行操作的时候使用js方法 var obj=$("#id" ...

  7. easyui tabs 真正刷新用法

    //刷新当前标签Tabs function RefreshTab(currentTab) { var url = $(currentTab.panel('options')).attr('href') ...

  8. How to create Managed Metadata Column

    This article introduce how to create/use managed metadata column from List. First, we need to config ...

  9. Azure IoT

    微软Azure IoT   国外物联网平台初探(二)——微软Azure IoT 马智 平台定位 连接设备.其它 M2M 资产和人员,以便在业务和操作中更好地利用数据. 连接 IoT 设备 将所有设备连 ...

  10. springmvc参数类型转换三种方式

    SpringMVC绑定参数之类型转换有三种方式:     1. 实体类中加日期格式化注解      @DateTimeFormat(pattern="yyyy-MM-dd hh:MM&quo ...