很长一段时间内,大多数网络通信方式都是阻塞模式,即:
· 客户端 向服务器端发出请求后,客户端会一直处于等待状态(不会再做其他事情),直到服务器端返回结果或者网络出现问题 。
· 服务器端同样如此,当在处理某个客户端 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阻塞模式(普通)的更多相关文章

  1. 网络I/O模型--02阻塞模式(多线程)

    当服务器收到客户端 X 的请求后(读取到所有请求数据后),将这个请求送入一个独立线程进行处理,然后主线程继续接收客户端 Y 的请求. 客户端一侧也可以使用一个子线程和服务器端进行通信.这样客户端主线程 ...

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

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

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

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

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

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

  5. 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 对于一个套接口上的 ...

  6. 网络IO模型 非阻塞IO模型

    网络IO模型 非阻塞IO模型 同步 一件事做完后再做另一件事情 异步 同时做多件事情 相对论 多线程 多进程 协程 异步的程序 宏观角度:异步 并发聊天 阻塞IO 阻塞IO的问题 一旦阻塞就不能做其他 ...

  7. 网络IO-阻塞、非阻塞、IO复用、异步

    网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...

  8. 转:PHP中实现非阻塞模式

    原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . ...

  9. Java I/O演进与Linux网络I/O模型

    参考文章: 简书-浅谈Linux五种IO:http://www.jianshu.com/p/486b0965c296 一.linux基础概念 1.1 内存空间 linux系统中的使用的是虚拟存储器,即 ...

随机推荐

  1. SQL与NOSQL

    一:关系型数据库 1.概念: 采用了关系模型来组织数据的数据库.简单讲,关系模型就是二维表格模型.二维表格在              数据库中我们称之为记录,列在数据库中我们成为字段. 2举例: M ...

  2. 【NOIP2013】 华容道 bfs预处理+bfs

    这一题我们考虑一个最裸的算法: 我们设$dp[i][j][k][l]$表示当前棋子在$(i,j)$且空格在$(k,l)$时的最小步数 然后显然随便转移一下就好了,时间复杂度为$O(q(nm)^2)$. ...

  3. POST 请求的 forHTTPHeaderField

    Response Headers(从服务器得到的回复的头) Field name Description Example Status Access-Control-Allow-Origin Spec ...

  4. POJ 2371

    #include<iostream> #include<stdio.h> #include<string> using namespace std; int com ...

  5. android动态权限获取

    android动态权限获取 Android6.0采用新的权限模型,只有在需要权限的时候,才告知用户是否授权,是在runtime时候授权,而不是在原来安装的时候 ,同时默认情况下每次在运行时打开页面时候 ...

  6. [转]asp.net core中的View Component

    解读ASP.NET 5 & MVC6系列(14):View Component http://www.cnblogs.com/TomXu/p/4496486.html

  7. predefClass中包含的符号

    Scope[ ||(boolean,boolean), &&(boolean,boolean), !=(int,int), !=(long,long), !=(float,float) ...

  8. Linux -- 使用笔记

    Linux新增分辨率1920x1080 sudo gedit /etc/default/grub 找到:#GRUB_GFXMODE=640x480 在这行下面加一行GRUB_GFXMODE=1920x ...

  9. 使用Apache Bench对网站性能进行测试

    使用Apache Bench对网站性能进行测试

  10. Ubuntu系统下开发人员常用工具、命令和技巧

    在新的Ubuntu系统安装完成后,开发人员一般需要下载.安装一些必备的工具,并进行一系列的环境配置等操作,本文对此做出一些总结,方便今后新开发环境的初始化. 一.文件常用安装目录和命令 一般的deb包 ...