1. import java.io.IOException;
    2. import java.net.InetSocketAddress;
    3. import java.nio.ByteBuffer;
    4. import java.nio.channels.SelectableChannel;
    5. import java.nio.channels.SelectionKey;
    6. import java.nio.channels.Selector;
    7. import java.nio.channels.ServerSocketChannel;
    8. import java.nio.channels.SocketChannel;
    9. import java.util.Iterator;
    10. import java.util.Set;
    11. /**
    12. * Author: tz_wl
    13. * Date: 2020/9/16 23:46
    14. * Content: 本示例为 select 单线程版本
    15. */
    16. public class select01single {
    17. //step 01 初始化全局变量 select server port
    18. private ServerSocketChannel server=null;
    19. private Selector selector =null;
    20. private int port =8092;
    21. //step 02 initServer 实例化 server selector 并将server注册到select的op_accept上面
    22. private void initServer() throws IOException {
    23. server = ServerSocketChannel.open();
    24. server.bind(new InetSocketAddress(port));
    25. server.configureBlocking(false);
    26. selector = Selector.open();
    27. server.register(selector, SelectionKey.OP_ACCEPT);//服务端的accept注册到selector
    28. }
    29. //step 03 start
    30. // while (true) { while(select.select(0)>0) { //当有02步骤的服务端注册到select ,
    31. // 取出 所有的 selectionKeys
    32. private void start() throws IOException {
    33. initServer();
    34. System.out.println("端口号为:"+ port +" ,服务正在启动中... ");
    35. while (true){
    36. //如果selector中有值,说明 server 端有 accept事件到达 select
    37. while (selector.select(0)>0){
    38. Set<SelectionKey> keySets = selector.selectedKeys();
    39. Iterator<SelectionKey> iter = keySets.iterator();
    40. while(iter.hasNext()){
    41. SelectionKey key = iter.next();
    42. iter.remove();
    43. if(key.isAcceptable()){ //如果select 是服务端触发的accept
    44. acceptHandler(key);
    45. }else if(key.isReadable()){ //如果 select 是客户端触发的 readable
    46. readHandler(key);
    47. }
    48. }
    49. }
    50. }
    51. }
    52. //04 acceptable
    53. // 当服务端有客户端连接 即是有 accetable 事件 , 注册 客户端的事件 到 select (顺带注册一个byteBuffer空间)
    54. // 通过 SelectionKey 获取 serverSocketChannel
    55. // 配置此serverSocketChannel的客户端socketChannel为非阻塞状态
    56. // 将socketChannel注册为 select 的 readable 并附赠 byteBuffer
    57. private void acceptHandler(SelectionKey key) throws IOException {
    58. ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
    59. SocketChannel clientChannel = ssc.accept();
    60. clientChannel.configureBlocking(false);
    61. ByteBuffer byteBuffer = ByteBuffer.allocate(20000);//注册此处在堆分配内存,不是栈
    62. clientChannel.register(selector,SelectionKey.OP_READ,byteBuffer);
    63. System.out.println("----------------------------------");
    64. System.out.println("新客户端"+clientChannel.getRemoteAddress());
    65. System.out.println("----------------------------------");
    66. }
    67. //05 处理客户端readable事件
    68. private void readHandler(SelectionKey key) {
    69. SocketChannel client = (SocketChannel)key.channel();
    70. ByteBuffer byteBuffer = (ByteBuffer)key.attachment();
    71. byteBuffer.clear();
    72. int count=0; //socketChannel中获取到的个数
    73. try {
    74. while (true) {
    75. count = client.read(byteBuffer);
    76. if (count > 0) { // 如果能够读到 客户端 的值 ,将此值 会写给客户端
    77. byteBuffer.flip();
    78. while (byteBuffer.hasRemaining()) {
    79. client.write(byteBuffer);
    80. }
    81. byteBuffer.clear(); //打扫卫生
    82. } else if (count == 0) { //如果读不到值 ,停止当前循环
    83. break;
    84. } else { //如果是-1 也就是客户端不连接了 , 关闭当前客户端
    85. System.out.println(" 客户端断开连接 "+ client.getRemoteAddress());
    86. client.close();
    87. break;
    88. }
    89. }
    90. }catch (IOException ex){
    91. ex.printStackTrace();
    92. }
    93. }
    94. public static void main(String[] args) throws IOException {
    95. select01single select01single = new select01single();
    96. select01single.start();
    97. }
    98. }