NIOServerDemo.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package cn.hhj.nio;
  2. import com.sun.org.apache.bcel.internal.generic.Select;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.net.SocketAddress;
  6. import java.nio.ByteBuffer;
  7. import java.nio.channels.SelectionKey;
  8. import java.nio.channels.Selector;
  9. import java.nio.channels.ServerSocketChannel;
  10. import java.nio.channels.SocketChannel;
  11. import java.util.Iterator;
  12. import java.util.Set;
  13. /**
  14. * NIO的操作过于繁琐,于是才有了Netty
  15. * Netty就是对这一系列非常繁琐的操作进行了封装
  16. *
  17. * Created by Tom.
  18. */
  19. public class NIOServerDemo {
  20. private int port = 8080;
  21. //准备两个东西
  22. //轮询器 Selector 大堂经理
  23. private Selector selector;
  24. //缓冲区 Buffer 等候区
  25. private ByteBuffer buffer = ByteBuffer.allocate(1024);
  26. //初始化完毕
  27. public NIOServerDemo(int port){
  28. //初始化大堂经理,开门营业
  29. try {
  30. this.port = port;
  31. ServerSocketChannel server = ServerSocketChannel.open();
  32. //我得告诉地址
  33. //IP/Port
  34. server.bind(new InetSocketAddress(this.port));
  35. //BIO 升级版本 NIO,为了兼容BIO,NIO模型默认是采用阻塞式
  36. server.configureBlocking(false);
  37. //大堂经理准备就绪,接客
  38. selector = Selector.open();
  39. //在门口翻牌子,正在营业
  40. server.register(selector, SelectionKey.OP_ACCEPT);
  41. } catch (Exception e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. public void listen(){
  46. System.out.println("listen on " + this.port + ".");
  47. try {
  48. //轮询主线程
  49. while (true){
  50. //大堂经理再叫号
  51. selector.select();
  52. //每次都拿到所有的号子
  53. Set<SelectionKey> keys = selector.selectedKeys();
  54. Iterator<SelectionKey> iter = keys.iterator();
  55. //不断地迭代,就叫轮询
  56. //同步体现在这里,因为每次只能拿一个key,每次只能处理一种状态
  57. while (iter.hasNext()){
  58. SelectionKey key = iter.next();
  59. iter.remove();
  60. //每一个key代表一种状态
  61. //没一个号对应一个业务
  62. //数据就绪、数据可读、数据可写 等等等等
  63. process(key);
  64. }
  65. }
  66. } catch (IOException e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. //具体办业务的方法,坐班柜员
  71. //每一次轮询就是调用一次process方法,而每一次调用,只能干一件事
  72. //在同一时间点,只能干一件事
  73. private void process(SelectionKey key) throws IOException {
  74. //针对于每一种状态给一个反应
  75. if(key.isAcceptable()){
  76. ServerSocketChannel server = (ServerSocketChannel)key.channel();
  77. //这个方法体现非阻塞,不管你数据有没有准备好
  78. //你给我一个状态和反馈
  79. SocketChannel channel = server.accept();
  80. //一定一定要记得设置为非阻塞
  81. channel.configureBlocking(false);
  82. //当数据准备就绪的时候,将状态改为可读
  83. key = channel.register(selector,SelectionKey.OP_READ);
  84. }
  85. else if(key.isReadable()){
  86. //key.channel 从多路复用器中拿到客户端的引用
  87. SocketChannel channel = (SocketChannel)key.channel();
  88. int len = channel.read(buffer);
  89. if(len > 0){
  90. buffer.flip();
  91. String content = new String(buffer.array(),0,len);
  92. key = channel.register(selector,SelectionKey.OP_WRITE);
  93. //在key上携带一个附件,一会再写出去
  94. key.attach(content);
  95. System.out.println("读取内容:" + content);
  96. }
  97. }
  98. else if(key.isWritable()){
  99. SocketChannel channel = (SocketChannel)key.channel();
  100. String content = (String)key.attachment();
  101. channel.write(ByteBuffer.wrap(("输出:" + content).getBytes()));
  102. channel.close();
  103. }
  104. }
  105. public static void main(String[] args) {
  106. new NIOServerDemo(8080).listen();
  107. }
  108. }