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

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:\Project\JavaWeb\HPArchitecture\BlockNIO\bin\slf4j-api-1.7.25.jar;D:\Project\JavaWeb\HPArchitecture\BlockNIO\bin\log4j-api-2.10.0.jar;D:\Project\JavaWeb\HPArchitecture\BlockNIO\bin\logback-core-1.2.3.jar;D:\Project\JavaWeb\HPArchitecture\BlockNIO\bin\logback-classic-1.2.3.jar testBlockSocket.SocketServerl
网络I/O模型--01阻塞模式(普通)的更多相关文章
- 网络I/O模型--02阻塞模式(多线程)
当服务器收到客户端 X 的请求后(读取到所有请求数据后),将这个请求送入一个独立线程进行处理,然后主线程继续接收客户端 Y 的请求. 客户端一侧也可以使用一个子线程和服务器端进行通信.这样客户端主线程 ...
- Socket 阻塞模式和非阻塞模式
阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...
- 简明网络I/O模型---同步异步阻塞非阻塞之惑
转自:http://www.jianshu.com/p/55eb83d60ab1 网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之 ...
- 网络I/O模型---同步异步阻塞非阻塞之惑
网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之改变.C10k的问题,让工程师们需要思考服务的性能与应用的并发能力. 网络应用需要 ...
- UNIX网络编程读书笔记:I/O模型(阻塞、非阻塞、I/O复用、信号驱动、异步)
I/O模型 UNIX下可用的5种I/O模型: (1)阻塞I/O (2)非阻塞I/O (3)I/O复用(select和poll) (4)信号驱动I/O(SIGIO) (5)异步I/O 对于一个套接口上的 ...
- 网络IO模型 非阻塞IO模型
网络IO模型 非阻塞IO模型 同步 一件事做完后再做另一件事情 异步 同时做多件事情 相对论 多线程 多进程 协程 异步的程序 宏观角度:异步 并发聊天 阻塞IO 阻塞IO的问题 一旦阻塞就不能做其他 ...
- 网络IO-阻塞、非阻塞、IO复用、异步
网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...
- 转:PHP中实现非阻塞模式
原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . ...
- Java I/O演进与Linux网络I/O模型
参考文章: 简书-浅谈Linux五种IO:http://www.jianshu.com/p/486b0965c296 一.linux基础概念 1.1 内存空间 linux系统中的使用的是虚拟存储器,即 ...
随机推荐
- postgresql 脏读-dirtied
共享缓冲区 在内存中读取或写入数据总是比在任何其他介质上更快.数据库服务器还需要用于快速访问数据的内存,无论是READ还是WRITE访问.在PostgreSQL中,这被称为"共享缓冲区&qu ...
- JavaScript 函数的4种调用方法
JavaScript 函数有 4 种调用方式. 每种方式的不同方式在于 this 的初始化. 作为一个函数调用 function myFunction(a, b) { return a * b; } ...
- eclipseGUI的可视化开发工具插件
一 各种GUI开发插件的特色 Eclipse并不自带GUI的可视化开发工具,那么如果要在Eclipse进行可视化的GUI开发,就需要依靠第三方的插件. 1. Visual Editor Eclip ...
- Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果
Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果 一.详细说明及代码 tc.py =============================================== ...
- 剑指offer四十二之和为S的两个数字
一.题目 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 二.思路 数列满足递增,设两个头尾两个指针i和j,若ai + ...
- python 批量模块导入(笔记)
环境:python3.6 目的:根据列表['os', 'sys', 're']中的字符串导入对应模块 from importlib import import_module modules = ['o ...
- Java之集合(十一)IdentityHashMap
转载请注明源出处:http://www.cnblogs.com/lighten/p/7381905.html 1.前言 查看JDK源码总是能发现一些新东西,IdentityHashMap也是Map的一 ...
- vue2.0实现底部导航切换效果
使用vue2.0写移动端的时候,经常会写底部导航效果,点击切换路由效果,实现图片和文字颜色切换.vue2.0也提供了很多ul框架供我们实现效果,今天就用原生的实现一个底部导航切换,直接上代码: 效果图 ...
- spark报错处理
Spark报错处理 1.问题:org.apache.spark.SparkException: Exception thrown in awaitResult 分析:出现这个情况的原因是spark启动 ...
- can/socket can
1. 概念 参考:Linux-CAN编程详解 can引脚: cn2: 15:CAN1_H 19 CAN1_L 根据每组报文开头的 11 位标识符(扩展帧为29位标识符.CAN 2.0A 规范)解释数据 ...