阻塞IO的含义

阻塞(blocking)IO :阻塞是指结果返回之前,线程会被挂起,函数只有在得到结果之后(或超时)才会返回

非阻塞(non-blocking)IO :非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

同步(synchronous)IO :应用阻塞在发送或接受数据的状态,直至数据成功传输(或返回失败),简单来说就是必须一件一件事做,等前一件做完了才能做下一件事

异步(asynchronous)IO :应用发送或接受数据后立即返回,实际处理这个调用的程序在完成后,通过状态、通知和回调来通知调用者

阻塞和非阻塞是获取资源的方式,同步和异步是程序如何处理资源的逻辑。

BIO网络编程

首先我们来看一段最基础的Java网络编程代码示例:

服务器端代码示例:

public class BIOServerV1 {

  public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept(); // 阻塞
System.out.println("收到新连接:" + request.toString());
try {
InputStream inputStream = request.getInputStream(); // 获取数据流
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String message;
while ((message = bufferedReader.readLine()) != null) {
if (message.length() == 0) {
break;
}
System.out.println("消息内容为:" + message);
}
System.out.println("收到数据,来自:" + request.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
request.close();
}
} serverSocket.close();
}
}

客户端代码示例:

public class BIOClient {

  public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8080);
OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String message = scanner.nextLine();
outputStream.write(message.getBytes(Charset.forName("UTF-8")));
scanner.close();
socket.close();
}
}

这个版本服务器端的代码同一时刻只能支持一个网络连接,在建立连接之后服务端线程会被阻塞,只有在已建立连接的客户端处理完数据关闭连接之后,后续的连接请求才能一个一个的处理,而为了能并发的处理多个请求我们在下一个版本中加入多线程的代码。

public class BIOServerV2 {

  private static ExecutorService executorService = Executors.newCachedThreadPool();

  public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept();
System.out.println("收到新连接:" + request.toString()); // 多线程接收多个连接
executorService.submit(
() -> {
try {
InputStream inputStream = request.getInputStream();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String message;
while ((message = bufferedReader.readLine()) != null) {
if (message.length() == 0) {
break;
}
System.out.println("消息内容为:" + message);
}
System.out.println("收到数据,来自:" + request.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
request.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
serverSocket.close();
}
}

这个版本的代码在加入多线程后可以并发的处理多个连接,但是它只能处理Java客户端的连接不能处理浏览器端的连接,而为了能与浏览器端交互我们需要了解HTTP协议的内容。

HTTP协议

HTTP协议请求数据包解析

HTTP协议响应数据包解析

HTTP协议响应状态码:

状态码 描述
1xx 临时响应,表示临时响应并需要请求者继续执行操作的状态码
2xx 成功,表示成功处理了请求的状态码
3xx 重定向,表示要完成请求,需要进一步操作。通常,这些状态码用来重定向
4xx 请求错误,这些状态码表示请求可能出错,妨碍了服务器的处理
5xx 服务器错误,这些状态码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错

BIO网络编程处理浏览器请求

在了解了HTTP协议的内容之后我们就可以依据HTTP协议的内容编写程序来处理浏览器请求。在之前多线程版本的代码之上我们需要对数据根据HTTP协议的内容进行处理,代码示例如下:

public class BIOServerV3 {

  private static ExecutorService executorService = Executors.newCachedThreadPool();

  public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功");
while (!serverSocket.isClosed()) {
Socket request = serverSocket.accept();
System.out.println("收到新连接:" + request.toString()); // 多线程接收多个连接
executorService.submit(
() -> {
try {
InputStream inputStream = request.getInputStream();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String message;
while ((message = bufferedReader.readLine()) != null) {
if (message.length() == 0) {
break;
}
// 拿到消息后可以解析消息拿到请求方法,请求数据等内容
System.out.println("消息内容为:" + message);
}
System.out.println("收到数据,来自:" + request.toString()); // 根据HTTP协议响应数据包返回数据给浏览器
OutputStream outputStream = request.getOutputStream();
outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
outputStream.write("Content-Length: 11\r\n\r\n".getBytes());
outputStream.write("Hello World".getBytes());
outputStream.flush(); } catch (IOException e) {
e.printStackTrace();
} finally {
try {
request.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
serverSocket.close();
}
}

以上就是Java BIO网络编程的基本内容,对于BIO来说一个请求对应一个线程,上下文切换占用的资源很重,同时由于大量并发情况下,其他接入的消息,只能一直等待,而目前对于性能,响应速度等的却要求越老越高,BIO网络编程使用的已经越来越少。使用的比较多的是Java NIO网络编程,该部分内容我们将在下一部分继续。

Java网络编程 -- BIO 阻塞式网络编程的更多相关文章

  1. UNIX网络编程——非阻塞式I/O(套接字)

    套接字的默认状态是阻塞的.这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待相应的操作完成.可能阻塞的套接字调用可分为以下4类: (1)输入操作,包括read,readv,rec ...

  2. java网络通信:同步阻塞式I/O模型(BIO)

    缺点:一个线程只能处理一个客户端连接 服务端: public class TimeServer { public static void main(String[] args) throws IOEx ...

  3. Java IO(3)非阻塞式输入输出(NIO)

    在上篇<Java IO(2)阻塞式输入输出(BIO)>的末尾谈到了什么是阻塞式输入输出,通过Socket编程对其有了大致了解.现在再重新回顾梳理一下,对于只有一个“客户端”和一个“服务器端 ...

  4. CLOS网络的无阻塞条件

    交换单元及网络 模拟信号数字化和时分复用基础 交换单元模型基本交换单元 交换网络 2.1模拟信号数字化和分时复用基础 模拟信号是指在是和幅度数值上连续变化的信号 数字信号是指在时间和幅度取值上离散的编 ...

  5. 阻塞式和非阻塞式IO

    有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...

  6. Linux NIO 系列(03) 非阻塞式 IO

    目录 一.非阻塞式 IO 附:非阻塞式 IO 编程 Linux NIO 系列(03) 非阻塞式 IO Netty 系列目录(https://www.cnblogs.com/binarylei/p/10 ...

  7. 阻塞式简易http服务器

    说明         使用java.net包的ServerSocket也是阻塞的,所以下面的实例把ServerSocketChannel换成ServerSocket效果一样. 后台代码 package ...

  8. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  9. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

随机推荐

  1. 洛谷P2001 硬币的面值 题解

    题目链接:https://www.luogu.org/problemnew/show/P2001 这题的数据范围吓得我很慌. 分析: 这道题蒟蒻本来想用背包的,但是发现m太大,一写肯定炸,然后看到数据 ...

  2. 2017day2

    系统模块: # Author: sonny# -*- coding:utf-8 -*-import sys; #print(sys.path);print(sys.argv);print(sys.ar ...

  3. Docker入门(初级)

    注意:命令基于centos7.5 一.什么是Docker? 通俗的理解,Docker就是虚拟机.但Docker不是虚拟机,Docker是对操作系统进行虚拟,而虚拟机是虚拟了一套或多套硬件,再在这虚拟的 ...

  4. 【TensorFlow 2】矩阵基础

    placeholder placeholder为tf中的占位符,用来保存数据.语法为: tf.placeholder(dtype, shape=None, name=None) dtype:数据类型  ...

  5. to_string()函数(C++)

    to_string函数,这是C++11新增的,使用非常方便,简单查了下:C++11标准增加了全局函数std::to_string 函数原型:string to_string (int val);str ...

  6. springboot整合elasticsearch(基于es7.2和官方high level client)

    前言 最近写的一个个人项目(传送门:全终端云书签)中需要用到全文检索功能,目前 mysql,es 都可以做全文检索,mysql 胜在配置方便很快就能搞定上线(参考这里),不考虑上手难度,es 在全文检 ...

  7. ubuntu下借助qt creator创建属于自己的共享库

    简介: 在 Windows 上,共享库由 .dll 表示:在 Linux 上,由 .so 表示. Shared Library的优势 共享库,又称动态库或so文件,顾名思义,它可以在可执行文件启动时加 ...

  8. bit、byte、kb、mb、g的区别

    1Byte=8bit1KB=1024Byte(字节)=8*1024bit1MB=1024KB1GB=1024MB1TB=1024GB bit是计算机数据的最小单元.要么是0,要么是1. byte 关键 ...

  9. Java学习多线程第一天

    内容介绍 Thread 线程创建 线程池 线程状态图 1 多线程 1.1     多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序 ...

  10. 数据结构之堆栈java版

    import java.lang.reflect.Array; /* 具体原理在c++版已经说的很清楚,这里不再赘述, 就提一点:java的泛型具有边界效应,一旦离开作用域立马被替换为object类型 ...