zoukankan      html  css  js  c++  java
  • 网络I/O模型--01阻塞模式(普通)

    很长一段时间内,大多数网络通信方式都是阻塞模式,即:
    · 客户端 向服务器端发出请求后,客户端会一直处于等待状态(不会再做其他事情),直到服务器端返回结果或者网络出现问题 。
    · 服务器端同样如此,当在处理某个客户端 A 发来的请求时,另 一个客户端 B 发来的请求会等待,直到服务器端的处理线程完成上一个请求的处理。

    image

         Java 对阻塞模式的支持,就是由 java. net 包中的 Socket 套接字功能完成的 。 这里要说明 一下 , Socket 套接字是 TCP/IP 等传输层协议在高级编程语言中的具体体现 。 例如客户端使用 TCP 协议连接这台服务器的时候,当 TCP 三次握手成功后,应用程序就会创建一个 Socket 套接字对象(注意,这时还没有进行数据内容的传输),当这个 TCP 连接出现数据传输时,Socket 套接字就会把数据传输的表现告诉程序员 。

    客户端代码

    package testBlockSocket;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.concurrent.CountDownLatch;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SocketClientDaemon {
        public static void main(String[] args) throws Exception {
            Integer clientNumber = 20;
            CountDownLatch countDownLatch = new CountDownLatch(clientNumber);
            // 分别开始启动这 20 个客户端
            for (int index = 0; index < clientNumber; index++, countDownLatch.countDown()) {
                SocketClientRequestThread client = new SocketClientRequestThread(countDownLatch, index);
                Thread thread = new Thread(client);
                thread.start();
            }
            // 这个同步锁不涉及具体的实验逻辑,只是保证守护线程在启动所有线程后,不会退出
            synchronized (SocketClientDaemon.class) {
                SocketClientDaemon.class.wait();
            }
        }
    }
    
    class SocketClientRequestThread implements Runnable {
    
        private final static Logger LOGGER = LoggerFactory.getLogger(SocketClientRequestThread.class);
    
        private CountDownLatch countDownLatch;
        // 这个线程的编号
        private Integer clientindex;
    
        // countDownLatch 是 Java 提供的线程同步计数器。
        // 当计数器数值减为 0 时,所有受其影响而阻塞的线程将会被激活。尽可能模拟并发请求的真实性(但实际上也并不是完全并发的)
        public SocketClientRequestThread(CountDownLatch countDownLatch, Integer clientindex) {
            this.countDownLatch = countDownLatch;
            this.clientindex = clientindex;
        }
    
        @Override
        public void run() {
            Socket socket = null;
            OutputStream clientRequest = null;
            InputStream clientResponse = null;
            try {
                socket = new Socket("localhost", 8888);
                clientRequest = socket.getOutputStream();
                clientResponse = socket.getInputStream();
                // 阻塞,直到 SocketClientDaemon 完成所有线程的启动,然后所有线程一起发送请求
                this.countDownLatch.await();
    
                // 发送请求信息
                clientRequest.write((" 这是第" + this.clientindex + " 个客户端的请求。").getBytes());
                clientRequest.flush();
                clientRequest.write((" 这是第" + this.clientindex + " 个客户端的  over ").getBytes());
                clientRequest.flush();
    
                // 在这里等待 , 直到服务器返回信息
                SocketClientRequestThread.LOGGER.info("第" + this.clientindex + "个客户端的请求发送完成, 等待服务器返回信息");
                int maxLen = 1024;
                byte[] contextBytes = new byte[maxLen];
                int realLen;
                String message = "";
                // 程序执行到这里 , 会一直等待服务器返回信息
                // (注意,前键是 in 和 out 都不能关闭,如果关闭了就收不到)
                while ((realLen = clientResponse.read(contextBytes, 0, maxLen)) != -1) {
                    message += new String(contextBytes, 0, realLen);
                    SocketClientRequestThread.LOGGER.info("接收 到 来自服务器的信息 :" + message);
                }
            } catch (Exception e) {
                SocketClientRequestThread.LOGGER.error(e.getMessage(), e);
            } finally {
                // 记得关闭连接
                try {
                    clientRequest.close();
                    clientResponse.close();
                    socket.close();
                } catch (Exception e) {
                    SocketClientRequestThread.LOGGER.error(e.getMessage(), e);
                }
            }
        }
    }

    服务端代码

    package testBlockSocket;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SocketServer1 {
    
        private final static Logger LOGGER = LoggerFactory.getLogger(SocketServer1.class);
    
        public static void main(String[] args) throws Exception {
    
            ServerSocket serverSocket = new ServerSocket(8888);
            try {
                while (true) {
                    // 这里 Java 通过 JNI 请求操作系统,并等待操作系统返回结果或出错
                    Socket socket = serverSocket.accept();
                    // 下面我们收取信息(这里还是阻塞式的, 一直等待 ,直到有数据可以接收 )
                    InputStream in = socket.getInputStream();
                    OutputStream out = socket.getOutputStream();
                    Integer sourcePort = socket.getPort();
                    int maxLen = 2048;
                    byte[] contextBytes = new byte[maxLen];
                    int realLen;
                    StringBuffer message = new StringBuffer();
                    // 试图读数据的时候,程序也会被阻塞,直到操作系统把网络传来的数据准备好 。
                    while ((realLen = in.read(contextBytes, 0, maxLen)) != -1) {
                        message.append(new String(contextBytes, 0, realLen));
                        // 我们假设读取到"over"关键字表示一段内容传输完成                    
                        if (message.indexOf("over") != -1) {
                            break;
                        }
                    }
                    // 下面打印信息
                    LOGGER.info("服务器收到来自于端口 : " + sourcePort + "的信息:" + message);
                    // 下面开始发送信息
                    out.write("回发响应信息 !".getBytes());
                    // 关闭
                    out.close();
                    in.close();
                    socket.close();
                }
            } catch (Exception e) {
                SocketServer1.LOGGER.error(e.getMessage(), e);
            } finally {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            }
        }
    }

     java -classpath ./;D:ProjectJavaWebHPArchitectureBlockNIOinslf4j-api-1.7.25.jar;D:ProjectJavaWebHPArchitectureBlockNIOinlog4j-api-2.10.0.jar;D:ProjectJavaWebHPArchitectureBlockNIOinlogback-core-1.2.3.jar;D:ProjectJavaWebHPArchitectureBlockNIOinlogback-classic-1.2.3.jar testBlockSocket.SocketServerl

  • 相关阅读:
    sql语句 之聚合函数
    UML类图几种关系的总结
    关于Object.defineProperty的get和set
    devDependencies和dependencies的区别
    函数声明和函数表达式的区别
    移动端滑屏滚动事件的问题(横向滑动阻止垂直页面滚动)
    使用Cordova和JQM在ios上需要注意的问题
    阻止事件冒泡,阻止默认事件,event.stopPropagation()和event.preventDefault(),return fal的区别
    有关闭包的总结
    CSS命名规范——BEM思想(非常赞的规范)
  • 原文地址:https://www.cnblogs.com/gispathfinder/p/9029798.html
Copyright © 2011-2022 走看看