• NIO与BIO服务器端对比


    本文利用NIO实现一个重复回复,客户端发送什么信息,客户端就会收到什么信息。

    主要是理解NIO与BIO的区别。客户端采用telnet进行测试,以下连接是Telnet安装的方法。

    Telnet的简单使用_武汉小喽啰的博客-CSDN博客_telnet

    注意!!!当使勇telnet连接成功到黑屏时候一定要用ctrl +] 进入客户端

    注意!!!当使勇telnet连接成功到黑屏时候一定要用ctrl +] 进入客户端

    注意!!!当使勇telnet连接成功到黑屏时候一定要用ctrl +] 进入客户端

    可以使用?/help 进行命令查看命令很少的。

    BIO即阻塞IO测试,发现以下两个地方会被阻塞,第一个客户端连接,第二个是客户端输入信息

    • Socket socket = serverSocket.accept();
    • InputStream is = socket.getInputStream();

    客户端连接服务端流程:

    【第一步】启动服务器--服务器运行到accept命令阻塞

    【第二步】连接客户端,服务器接收客户端,阻塞到 getInputStream() 等待客户端发送信息。

    可以看出来,一个线程为客户端服务,直到客户端断开连接

    【代码】

    1. package cn.msf.bio;
    2. import java.io.IOException;
    3. import java.io.InputStream;
    4. import java.net.ServerSocket;
    5. import java.net.Socket;
    6. /**
    7. * @author: msf
    8. * @date: 2022/11/22
    9. */
    10. public class BIO {
    11. public static void main(String[] args) {
    12. try {
    13. ServerSocket serverSocket = new ServerSocket(10101);
    14. System.out.println("服务端启动");
    15. while (true) {
    16. // 获取一个套接字(阻塞)
    17. Socket socket = serverSocket.accept();
    18. System.out.println("来了一个客户端");
    19. hander(socket);
    20. }
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. private static void hander(Socket socket) {
    26. byte[] bytes = new byte[1024];
    27. int len = 0;
    28. try {
    29. // 阻塞等待。
    30. InputStream is = socket.getInputStream();
    31. // 将信息读到bytes中。
    32. while ((len = is.read(bytes)) != -1) {
    33. System.out.println(new String(bytes, 0, len));
    34. }
    35. } catch (IOException e) {
    36. e.printStackTrace();
    37. } finally {
    38. System.out.println("关闭socket");
    39. try {
    40. socket.close();
    41. } catch (IOException e) {
    42. e.printStackTrace();
    43. }
    44. }
    45. }
    46. }

    NIO实现测试

    【第一步】建立服务器端,这里使用的命令是

    1. ServerSocketChannel serverChannel = ServerSocketChannel.open();
    2.         // 设置为不阻塞
    3. serverChannel.configureBlocking(false);
    4.         // 设置socket的连接接口
    5. serverChannel.socket().bind(new InetSocketAddress("localhost",port));

    【第二步】开启selector相当找了一个服务员,为客户端服务

    1. // 启动一个选择器
    2. selector = Selector.open();
    3. serverChannel.register(selector, SelectionKey.OP_ACCEPT);

     【第三步】监听客户端连接

    1. public void listen() throws IOException {
    2. System.out.println("服务端启动成功");
    3. while (true) {
    4. // 当服务端注册的时间到达后,返回;否则会一直阻塞
    5. selector.select();
    6. selector.wakeup();
    7. Iterator ite = selector.selectedKeys().iterator();
    8. while (ite.hasNext()) {
    9. SelectionKey key = ite.next();
    10. ite.remove();
    11. // 处理事件的类型
    12. handler(key);
    13. }
    14. }
    15. }

    【第四步】为不同客户端处理不同的事件。

    可以达到一对多服务,不会想BIO一样阻塞在getinputstream哪里只等待一个客户端

     

    1. private void handler(SelectionKey key) throws IOException {
    2. if (key.isAcceptable()) {
    3. // 说明是注册事件
    4. handlerAccept(key);
    5. } else if (key.isReadable()) {
    6. handlerRead(key);
    7. }
    8. }

    【完整代码】 

    1. package cn.msf.nio;
    2. import java.io.IOException;
    3. import java.net.InetSocketAddress;
    4. import java.nio.ByteBuffer;
    5. import java.nio.channels.*;
    6. import java.nio.charset.StandardCharsets;
    7. import java.util.Date;
    8. import java.util.Iterator;
    9. /**
    10. * @author: msf
    11. * @date: 2022/11/23
    12. */
    13. public class NIOServer {
    14. private Selector selector;
    15. public static void main(String[] args) throws IOException {
    16. NIOServer server = new NIOServer();
    17. server.initServer(8000);
    18. server.listen();
    19. }
    20. public void initServer(int port) throws IOException {
    21. // 获得一个ServerSocket 通道
    22. ServerSocketChannel serverChannel = ServerSocketChannel.open();
    23. // 设置为不阻塞
    24. serverChannel.configureBlocking(false);
    25. // 设置socket的连接接口
    26. serverChannel.socket().bind(new InetSocketAddress("localhost",port));
    27. // 启动一个选择器
    28. selector = Selector.open();
    29. serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    30. }
    31. public void listen() throws IOException {
    32. System.out.println("服务端启动成功");
    33. while (true) {
    34. // 当服务端注册的时间到达后,返回;否则会一直阻塞
    35. selector.select();
    36. selector.wakeup();
    37. Iterator ite = selector.selectedKeys().iterator();
    38. while (ite.hasNext()) {
    39. SelectionKey key = ite.next();
    40. ite.remove();
    41. // 处理事件的类型
    42. handler(key);
    43. }
    44. }
    45. }
    46. private void handler(SelectionKey key) throws IOException {
    47. if (key.isAcceptable()) {
    48. // 说明是注册事件
    49. handlerAccept(key);
    50. } else if (key.isReadable()) {
    51. handlerRead(key);
    52. }
    53. }
    54. public void handlerAccept(SelectionKey key) throws IOException {
    55. // 当有事件来了,获得之前的服务端
    56. ServerSocketChannel server = (ServerSocketChannel) key.channel();
    57. // 获得客户端的通道--相当于客户端
    58. SocketChannel channel = server.accept();
    59. channel.configureBlocking(false);
    60. System.out.println("客户端连接");
    61. channel.register(this.selector,SelectionKey.OP_READ);
    62. }
    63. private void handlerRead(SelectionKey key) throws IOException {
    64. // 服务器可读消息,得到事件发生的Socket通道。
    65. SocketChannel channel = (SocketChannel) key.channel();
    66. // 创建缓冲区
    67. ByteBuffer buffer = ByteBuffer.allocate(1024);
    68. int read = channel.read(buffer);
    69. if (read > 0) {
    70. byte[] data = buffer.array();
    71. String msg = new String(data).trim();
    72. System.out.println("服务器收到消息: " + msg);
    73. ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
    74. // 将消息发送给客户端
    75. channel.write(outBuffer);
    76. } else {
    77. channel.close();
    78. }
    79. }
    80. }

  • 相关阅读:
    亚马逊收到CPSC查验通知后卖家需要怎么弄?ASTM F963标准测试 ,CPC认证
    导出本地服务到Public Network,需有密码才能访问,7天有效时间
    利用tomcat部署 springmvc项目的问题
    【算法基础】用数组模拟栈和队列
    关于美国服务器IP的几个常见问题
    unbuntu配置Samba服务器
    【菜鸡学艺--Vue2--002】[基础指令&[条件与循环]
    Redis实用功能汇总
    ActiveMQ如何处理重复消息?如何保证消息的有序性?如何处理消息堆积?
    shim error: docker-runc not installed on system
  • 原文地址:https://blog.csdn.net/abc123mma/article/details/128008399