• 网络I/O模型--04非阻塞模式(解除accept()、 read()方法阻塞)的基础上加入多线程技术


          由于应用程序级别并没有使用多线程技术,这就导致了应用程序只能一个一个地对Socket 套接字进行处理。这个 Socket 套接宇没有处理完,就没法处理下一个 Socket 套接字 。针对这个 问题还是可以进行改进的:让应用程序层面上各个 Socket 套接字的处理相互不影响 。

    服务端代码

    package testBlockSocket;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketTimeoutException;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    //通过加入线程的概念,让 Socket Server 能够在应用层面
    //通过非阻塞的方式同时处理多个 Socket 套接字
    public class SocketServer4AllTimeoutAndMultiThread {
        private final static Logger LOGGER = LoggerFactory.getLogger(SocketServer4AllTimeoutAndMultiThread.class);
        private static Object xWait = new Object();
    
        public static void main(String[] args) throws Exception {
            ServerSocket serverSocket = new ServerSocket(8888);
            serverSocket.setSoTimeout(100);
            try {
                while (true) {
                    Socket socket = null;
                    try {
                        socket = serverSocket.accept();
                    } catch (SocketTimeoutException el) {
                        // ===================
                        // 执行到这里,说明本次 accept()方法没有接收到任何 TCP 连接主线程在这里就可以做一些事情,记为 x
                        // ==================
                        synchronized (SocketServer4AllTimeoutAndMultiThread.xWait) {
                            LOGGER.info("这次没有接收到 TCP 连接,等待10 毫秒,模拟事件x 的处理时间 ");
                            SocketServer4AllTimeoutAndMultiThread.xWait.wait(10);
                        }
                        continue;
                    }
                    // 业务处理过程可以交给一个线程(这里可以使用线程池)
                    // 注意 , 线程的创建过程是很耗资源和时间的
    
                    // 最终改变不了 accept ( )方法只能一个一个地接收 Socket 连接的情况
                    SocketServerThreadWithTimeOut socketServerThread = new SocketServerThreadWithTimeOut(socket);
                    new Thread(socketServerThread).start();
                }
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            } finally {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            }
        }
    }
    
    // 当然,接收到客户端的 Socket 后,业务的处理过程可以交给一个线程来做
    class SocketServerThreadWithTimeOut implements Runnable {
    
        private final static Logger LOGGER = LoggerFactory.getLogger(SocketServerThreadWithTimeOut.class);
        private Socket socket;
    
        public SocketServerThreadWithTimeOut(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();
                Integer sourcePort = socket.getPort();
                int maxLen = 2048;
                byte[] contextBytes = new byte[maxLen];
                int realLen;
                StringBuffer message = new StringBuffer();
                // 下面我们收取信息
                this.socket.setSoTimeout(10);
                BIORead: while (true) {
                    try {
                        while ((realLen = inputStream.read(contextBytes, 0, maxLen)) != -1) {
                            message.append(new String(contextBytes, 0, realLen));
                            // 我们同样假设读取到"over"关键字,表示业务内容传输完成
                            if (message.indexOf("over") != -1) {
                                break BIORead;
                            }
                        }
                    } catch (SocketTimeoutException e2) {
                        // =================
                        // 执行到这里,说明本次 read ()方法没有接收到任何数据流主线程在这里又可以做一些事情,记为 Y
                        // =================
                        LOGGER.info("这次没有接收到任务数据报文,等待 10 ~盖秒 ,模拟事件 Y 的处理时间 ");
                        continue;
                    }
                }
                // 下面打印信息
                Long threadId = Thread.currentThread().getId();
                SocketServerThreadWithTimeOut.LOGGER.info("服务器(线程 :" + threadId + ")收到来自于端口 :" + sourcePort + "的信息: " + message);
                // 下面开始发送信息
                outputStream.write("回发响应信息:".getBytes());
                // 关闭 in 和 out 对象
                inputStream.close();
                outputStream.close();
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
        }
    }

    引入了多线程技术后, I/O的处理吞吐量有了提高(实际上并不显著) ,因为 acceptO方法为“同步”工作的情况依然存在 。

  • 相关阅读:
    springboot启动流程(三)Environment简介
    JavaWeb【一、简介】
    JavaJDBC【七、JDBC升级版简介】
    JavaJDBC【六、连接池】
    JavaJDBC【五、事务】
    JavaJDBC【四、存储过程的使用】
    JavaJDBC【三、增删改查】
    JavaJDBC【二、Mysql包加载与使用】
    JavaJDBC【一、概述】
    Java注解【五、注解实战】
  • 原文地址:https://www.cnblogs.com/gispathfinder/p/9029901.html
Copyright © 2020-2023  润新知