网络I/O模型--03非阻塞模式(ServerSocket与Socket的超时处理)--解除accept()、 read()方法阻塞

对于阻塞方式的一种改进是在应用程序层面上将 “一直等待 ”的状态主动打开:

这种模式下,应用程序的线程不再一直等待操作系统的 I/O状态,而是在等待一段时间后就解除阻塞。如果没有得到想要的结果,则再次进行相同的操作 。 这样的工作方式,保证了应用程序的线程不会一直阻塞,而可以进行一些其他工作一一例如软件业务层面上暂时不需要这些网络数据的操作过程

服务端代码(对accept()方法也解除阻塞)

package testBlockSocket;

import java.io.IOException;
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连接
public class SocketServer3SocketTimeout {
    private final static Logger LOGGER = LoggerFactory.getLogger(SocketServer3SocketTimeout.class);
    private static Object xWait = new Object();

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8888);
            // 设定阻塞时间
            serverSocket.setSoTimeout(100);
            while (true) {
                Socket socket = null;
                try {
                    // 程序不会一直在这里阻塞了
                    socket = serverSocket.accept();
                } catch (SocketTimeoutException el) {
                    // 执行到这里,说明本次 accept ()方法没有接收到任何数据报文,主线程在这里就可以做一些事情,记为 x
                    synchronized (SocketServer3SocketTimeout.xWait) {
                        LOGGER.info("这次没有接收到 TCP 连接,据报文,等待 10 毫秒,模拟事件 x 的处理时间");
                        SocketServer3SocketTimeout.xWait.wait(10);
                    }
                    continue;
                }
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                Integer sourcePort = socket.getPort();
                int maxLen = 2048;
                byte[] contextBytes = new byte[maxLen];
                int realLen;
                StringBuffer message = new StringBuffer();
                // 以下接收数据,与 7.2.1 节中的代码处理过程一致
                while ((realLen = inputStream.read(contextBytes, 0, maxLen)) != -1) {
                    message.append(new String(contextBytes, 0, realLen));
                    // 我们假设读取到"over"关键字表示一段内容传输完成
                    if (message.indexOf("over") != -1) {
                        break;
                    }
                }
                // 下面打印信息
                LOGGER.info("服务器收到来自于端口 : " + sourcePort + "的信息:" + message);
                // 下面开始发送信息
                outputStream.write("回发响应信息 !".getBytes());
                // 关闭
                outputStream.close();
                inputStream.close();
                socket.close();
            }
        } catch (Exception e) {
            SocketServer3SocketTimeout.LOGGER.error(e.getMessage(), e);
        } finally {
            // 关闭连接
            if (serverSocket != null) {
                serverSocket.close();
            }
        }
    }
}

服务端代码改进(对accept()和read()方法解除阻塞)

package testBlockSocket;

import java.io.IOException;
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连接
//通过非阻塞的方式同时处理read()
public class SocketServer3SocketTimeoutReadTimeout {
    private final static Logger LOGGER = LoggerFactory.getLogger(SocketServer3SocketTimeoutReadTimeout.class);
    private static Object xWait = new Object();

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8888);
            // 设定阻塞时间
            serverSocket.setSoTimeout(100);
            while (true) {
                Socket socket = null;
                try {
                    socket = serverSocket.accept();
                } catch (SocketTimeoutException el) {
                    // ===================
                    // 执行到这里,说明本次 accept()方法没有接收到任何 TCP 连接主线程在这里就可以做一些事情,记为 x
                    // ==================
                    synchronized (SocketServer3SocketTimeoutReadTimeout.xWait) {
                        LOGGER.info("这次没有接收到 TCP 连接,等待10 毫秒,模拟事件x 的处理时间 ");
                        SocketServer3SocketTimeoutReadTimeout.xWait.wait(10);
                    }
                    continue;
                }
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                Integer sourcePort = socket.getPort();
                int maxLen = 2048;
                byte[] contextBytes = new byte[maxLen];
                int realLen;
                StringBuffer message = new StringBuffer();
                // 下面我们收取信息(非阻塞方式, read()方法的等待超时时间)
                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;
                    }
                }
                // 下面打印信息
                LOGGER.info("服务器收到来自子端口:" + sourcePort + "的信息:" + message);
                // 下面开始发送信息
                outputStream.write(" 回发响应信息 !".getBytes());
                // 关闭in和 out 对象
                inputStream.close();
                outputStream.close();
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            // 关闭服务
            if (serverSocket != null) {
                serverSocket.close();
            }
        }
    }
}

对阻塞模型的改进 : 让 TCP 连接和数据读取这两个过程,都变成了“非阻塞”方式 。

这种方式对网络I/O 性能的提升意义不大,原因是这种处理方式实际上并没有解决accept()方法、 read()方法阻塞的根本问题 。 根据上文的描述, accept()方法、 read()方法阻塞的根本问题是底层接收数据时采用 了操作系统提供的“同步 I/O”工作方式。这两次改进过程,只是解决了I/O 操作的两步中的第一步:将程序层面的阻塞方式变成了非阻塞方式 。

原文地址:https://www.cnblogs.com/gispathfinder/p/9029885.html

时间: 2024-10-09 11:58:29

网络I/O模型--03非阻塞模式(ServerSocket与Socket的超时处理)--解除accept()、 read()方法阻塞的相关文章

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

由于应用程序级别并没有使用多线程技术,这就导致了应用程序只能一个一个地对Socket 套接字进行处理.这个 Socket 套接宇没有处理完,就没法处理下一个 Socket 套接字 .针对这个 问题还是可以进行改进的:让应用程序层面上各个 Socket 套接字的处理相互不影响 . 服务端代码 package testBlockSocket; import java.io.InputStream; import java.io.OutputStream; import java.net.Server

严格模型和非严格模式的区别

严格模式 use strict,就是在代码的头部加上use strict function test(){ console.log(arguments.callee) console.log(123) } test() 把这段代码放到浏览器是不会报错的,但是,如果严格模式是会报错的,小伙伴们可以拿过去代码去加上use strict在自己的浏览器上试试 因为严格模式是没有arguments,caller,callee 说一下这个callee 当函数本身 function test(){ var i

深入 CSocket 编程之阻塞和非阻塞模式

有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server (客户端 / 服务端)的网络聊天和传输文件的程序 ( 详见: 源代码参考 ) ,在调试这些程序的过程中,追踪深入至 CSocket 类核心源码 Sockcore.cpp , 对于CSocket 类的运行机制可谓是一览无遗,并且对于阻塞和非阻塞方式下的 socket 程序的编写也是稍有体会. 阅读本

非阻塞模式下connect 成功失败判断

将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK; 即: flags = fcntl(sockfd, F_GETFL, 0);                        //获取文件的flags值. fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);   //设置成非阻塞模式: 同时在接收和发送数据时,需要使用MS

服务器编程心得(四)—— 如何将socket设置为非阻塞模式

1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ int type, _In_ int protocol ); SOCKET WSASocket( _In_ int af, _In_ int type, _In_ int protocol, _In_ LPWSAPROTOCOL_INFO lpProtocolInfo, _In_ GROUP g,

网络I/O模型---同步异步阻塞非阻塞之惑

网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之改变.C10k的问题,让工程师们需要思考服务的性能与应用的并发能力. 网络应用需要处理的无非就是两大类问题,网络I/O,数据计算.相对于后者,网络I/O的延迟,给应用带来的性能瓶颈大于后者.网络I/O的模型大致有如下几种: 同步模型(synchronous I/O) 阻塞I/O(bloking I/O) 非阻塞I/O(non-blocking I/O) 多路复用I/O(multi

在网络I/O模型方面Netty采用基于非阻塞I/O的实现

第一层:Reactor通信调度层.该层的主要职责就是监听网络的连接和读写操作,负责将网络层的数据读取到内存缓冲区中,然后触发各种网络事件,例如连接创建.连接激活.读事件.写事件等,将这些事件触发到Pipeline中,再由Pipeline充当的职责链来进行后续的处理. 第二层:职责链Pipeline层.负责事件在职责链中有序的向前(后)传播,同时负责动态的编排职责链.Pipeline可以选择监听和处理自己关心的事件. 第三层:业务逻辑处理层,一般可分为两类:a. 纯粹的业务逻辑处理,例如日志.订单

转:PHP中实现非阻塞模式

原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . 先说一下网络请求并发 理论描述 假设有一个client,程序逻辑是要请求三个不同的server,处理各自的响应.传统模型当然是顺序执行,先发送第一个请求,等待收到响应数据后再发送第二个请求,以此类推.就像是单核CPU,一次只能处理一件事,其他事情被暂时阻塞.而并发模式可以让三个server同时处理

PHP非阻塞模式

PHP非阻塞模式 by 尘缘 on 七月 31st, 2014 // Filed Under → php 让PHP不再阻塞当PHP作为后端处理需要完成一些长时间处理,为了快速响应页面请求,不作结果返回判断的情况下,可以有如下措施: 一.若你使用的是FastCGI模式,使用fastcgi_finish_request()能马上结束会话,但PHP线程继续在跑. 帮助 01 02 03 04 05 06 07 08 09 10 echo"program start."; file_put_c