网络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系统中的使用的是虚拟存储器,即 ...
随机推荐
- AngularJS入门之数据绑定
本篇我们看一下AngularJS中的数据绑定.虽然我们直到这篇才提到数据绑定,但事实上在前面几篇中我们已经非常熟练的运用AngularJS的数据绑定功能了! ngBind(ng-bind)/ {{ e ...
- Netty核心概念(10)之内存管理
1.前言 之前的章节已经将启动demo中能看见的内容都分析完了,Netty的一个整体样貌都在第8节线程模型最后给的图画出来了.这些内容解释了Netty为什么是一个异步事件驱动的程序,也解释了Netty ...
- static变量生命周期小研究
A页面:定义一个普通类,类包含一个静态变量a,值为:111111111111111111 B页面:修改a的值为:22222222222222 C页面:用来查看a的值 1.在vs2008中,先打开B,再 ...
- Weinre远程调试工具
1.Weinre是什么? Weinre全称 Web Inspector Remote,是一个简单好用的远程调试工具.我们可以在自己的PC上修改对应网页的页面元素.样式,或是查看Javascript变量 ...
- wp 自定义分页函数
function kerui_pagination($query_string){ global $posts_per_page, $paged; $my_query = new WP_Query($ ...
- webSQL的基本操作
1.html5以来,数据的前端存储已经有了很大进步.这里简单些一下webSQL的基本用法.代码如下: <!DOCTYPE html> <html> <head> & ...
- windows下安装并使用redis
一.安装前首先了解一下phpinfo里面的一些信息,能否正确安装非常有帮助. (下图是我的本机环境) compiler :编译器 Architecture :CPU架构 Configuration F ...
- python笔记09-----装饰器,生成器,迭代器
1.装饰器 定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器的知识储备: 1. 函数即“变 ...
- InterView之PHP
PHP HTTP Keep-Alive的作用 作用 Keep-Alive:使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接.Web服务器 ...
- [PY3]——面向对象编程(1)
类的对象 有三种对象 可以做什么操作 包括什么属性 类对象 属性引用.实例化 函数方法.内置的属性.类变量 实例对象 属性引用 函数方法.类变量.实例变量 方法对象 1. 类对象.实例对象.方法对象 ...