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

这种模式下,应用程序的线程不再一直等待操作系统的 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 操作的两步中的第一步:将程序层面的阻塞方式变成了非阻塞方式 。

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

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

    由于应用程序级别并没有使用多线程技术,这就导致了应用程序只能一个一个地对Socket 套接字进行处理.这个 Socket 套接宇没有处理完,就没法处理下一个 Socket 套接字 .针对这个 问题还是 ...

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

    有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server ...

  3. socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto

    socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...

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

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

  5. 没搞清楚网络I/O模型?那怎么入门Netty

    微信搜索[阿丸笔记],关注Java/MySQL/中间件各系列原创实战笔记,干货满满. 本文是Netty系列笔记第二篇 Netty是网络应用框架,所以从最本质的角度来看,是对网络I/O模型的封装使用. ...

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

    转自:http://www.jianshu.com/p/55eb83d60ab1 网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之 ...

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

    网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之改变.C10k的问题,让工程师们需要思考服务的性能与应用的并发能力. 网络应用需要 ...

  8. 网络I/O模型--01阻塞模式(普通)

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

  9. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

随机推荐

  1. Ejb3 + Jboss8 出现Session id hasn't been set for stateful component

    Ejb 3 + JBoss 8  在使用客户端远程访问有状态的Ejb对象时,出现ERROR: Session id hasn't been set for stateful component 出现该 ...

  2. java的Arrays工具类

    1年多了,jdk还不是很熟,补补. package lhy.core.util; import java.util.Arrays; import java.util.List; public clas ...

  3. Tomcat性能调优-让小猫飞奔

    一.总结前一天的学习 从“第三天”的性能测试一节中,我们得知了决定性能测试的几个重要指标,它们是: ü   吞吐量 ü   Responsetime ü   Cpuload ü   MemoryUsa ...

  4. linux文件映射到windows(方便用虚拟机搭建linux服务器,用本地windows代码编辑)

    1,安装docker: https://docs.docker.com/install/linux/docker-ce/centos/ 2,linux上创建好需要共享的目录 /data/share(可 ...

  5. ActiveRecord::Fixture::FixtureError: table "users" has no column named "activated_at".

    window 7+ruby2.33+rails5.0. 在测试的时候 rails test 报固件fixture错误: 没有某列字段存在 虽然可以直接通过开发框架去修改字段,但是开发过程中应该通过迁移 ...

  6. Fiddler Web Debugger安装后与浏览器之间的常用设置(辅助爬虫)(图文详解)

    不多说,直接上干货! 怎么让我们的浏览经过代理服务呢?如下来正确设置: 这里有个经验,最好用历史低版本的火狐浏览器.比如 http://ftp.mozilla.org/pub/firefox/rele ...

  7. webSQL的基本操作

    1.html5以来,数据的前端存储已经有了很大进步.这里简单些一下webSQL的基本用法.代码如下: <!DOCTYPE html> <html> <head> & ...

  8. Java虚拟机(三):JVM垃圾回收机制

    概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方 ...

  9. HTML引入CSS样式的四种方法

    在HTML中引入CSS的方法主要有四种,它们分别是行内式.内嵌式.链接式和导入式. 1.行内式          行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐 ...

  10. bzoj 4912: [Sdoi2017]天才黑客

    Description Solution 这个题和点没什么关系 , 之和边与边之间关系有关 , 我们就把边看作点 , 边权就是 \(lcp\) , 点权看作这条边本来的权值. 现在考虑两两连边 , \ ...