Java网络编程 -- BIO 阻塞式网络编程
阻塞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 阻塞式网络编程的更多相关文章
- UNIX网络编程——非阻塞式I/O(套接字)
套接字的默认状态是阻塞的.这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待相应的操作完成.可能阻塞的套接字调用可分为以下4类: (1)输入操作,包括read,readv,rec ...
- java网络通信:同步阻塞式I/O模型(BIO)
缺点:一个线程只能处理一个客户端连接 服务端: public class TimeServer { public static void main(String[] args) throws IOEx ...
- Java IO(3)非阻塞式输入输出(NIO)
在上篇<Java IO(2)阻塞式输入输出(BIO)>的末尾谈到了什么是阻塞式输入输出,通过Socket编程对其有了大致了解.现在再重新回顾梳理一下,对于只有一个“客户端”和一个“服务器端 ...
- CLOS网络的无阻塞条件
交换单元及网络 模拟信号数字化和时分复用基础 交换单元模型基本交换单元 交换网络 2.1模拟信号数字化和分时复用基础 模拟信号是指在是和幅度数值上连续变化的信号 数字信号是指在时间和幅度取值上离散的编 ...
- 阻塞式和非阻塞式IO
有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...
- Linux NIO 系列(03) 非阻塞式 IO
目录 一.非阻塞式 IO 附:非阻塞式 IO 编程 Linux NIO 系列(03) 非阻塞式 IO Netty 系列目录(https://www.cnblogs.com/binarylei/p/10 ...
- 阻塞式简易http服务器
说明 使用java.net包的ServerSocket也是阻塞的,所以下面的实例把ServerSocketChannel换成ServerSocket效果一样. 后台代码 package ...
- 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...
- [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网 ...
随机推荐
- Excel催化剂开源第35波-图片压缩及自动旋转等处理
Excel催化剂在图片处理方面,也是做到极致化,一般的Excel插件插入图片是原图插入或不可控制压缩比例地方式插入图片至Excel当中,但Excel催化剂的插入图片,是开发了可调节图片大小的插入方式, ...
- python 面向对象编程 - 小游戏
面向对象写的小游戏 欢迎玩耍 class Omnicience: camp = 'Omniscience' def __init__(self, name, atk=100, hp=1000, mp= ...
- C#3.0新增功能09 LINQ 基础07 LINQ 中的查询语法和方法语法
连载目录 [已更新最新开发文章,点击查看详细] 介绍性的语言集成查询 (LINQ) 文档中的大多数查询是使用 LINQ 声明性查询语法编写的.但是在编译代码时,查询语法必须转换为针对 .NET ...
- python+selenium实现163邮箱登陆—iframe动态ID定位 及常用定位方法
今天发现之前的登录163邮箱脚本定位不到iframe了,原因是iframe拼接了动态ID,修改后的脚本如下: from selenium import webdriver driver = webdr ...
- Java集合系列(一):集合的定义及分类
1. 集合的定义 什么是集合呢? 定义:集合是一个存放对象的引用的容器. 在Java中,集合位于java.util包下. 2. 集合和数组的区别(面试常问) 提到容器,就会想起数组,那么集合和数组的区 ...
- Djangou中使用cookie和session
一.会话跟踪 我们先需要了解是什么是会话!可以把会话理解为客户端与服务器之间的一次会话,在一次会话中可能会包含多次请求和响应,例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器, ...
- Nginx搭建详细
Linux 安装Nginx搭建详细内容 进入:/usr/java/nginx位置下载nginx: wget et http://nginx.org/download/nginx-1.8.0.tar.g ...
- 【MySQL】导出长数字到 Excel 避免转为科学计数法方法
MySQL 导出比较长的数字到 Excel 时,最后几位会变成 0,解决方法如下: 如果只需要导出展示.打印:可使用 CONCAT("\t",str) 如果需要后续处理,引用,最好 ...
- 新浪微博SSO授权后回调客户端没有执行sinaweiboDidLogIn&无法返回应用
TARGETS --> URL Types --> 添加 --> 在URL Schemes里填上sinaweibosso.XXXX(AppKey),Identifier这里可以随机 ...
- 使用f12定位bug
为什么找到网站中的bug后还要去分析它到底是属于前端bug还是后端bug 三个原因: 1.在一些公司,一个系统可能是由前端团队和后端团队共同开发出来的,因此在分配bug的时候,不同模块的bug一般都会 ...