网络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方法为“同步”工作的情况依然存在 。

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

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

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

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

对于阻塞方式的一种改进是在应用程序层面上将 "一直等待 "的状态主动打开: 这种模式下,应用程序的线程不再一直等待操作系统的 I/O状态,而是在等待一段时间后就解除阻塞.如果没有得到想要的结果,则再次进行相同的操作 . 这样的工作方式,保证了应用程序的线程不会一直阻塞,而可以进行一些其他工作一一例如软件业务层面上暂时不需要这些网络数据的操作过程 服务端代码(对accept()方法也解除阻塞) package testBlockSocket; import java.io.IOExcep

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

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

delphi Winsock非阻塞模式详解

delphi Winsock非阻塞模式详解   Winsockt的TClientSocket设置ClientType的属性为ctNonBlocking.则通讯模式为非阻塞模式. ctBlocking为阻塞模式,这里说一下阻塞与非阻塞的一些区别. ctBlocking模式当客户端请求数据后,线程阻塞不继续执行,直到服务端返回数据,客户端将据需执行,并读取数据. 然而阻塞模式的缺陷还是比较大的,经常会使程序死掉或者假死.当服务端发送较大的文件时,阻塞模式基本废掉了,由于数据缓冲较小,不能及时的获取数

非阻塞模式下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

网络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同时处理

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

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

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