[编织消息框架][网络IO模型]BIO
既然跟网络内容有关就不得不学习网络IO模型,时代在进步,技术也在进步,采取使用那种网络IO模型就已经确定应用程序规模
阻塞IO(blocking IO)
在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:
图1 阻塞IO
大部分的IO接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来
所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。
对于网络编程,在第一阶段系统内核阻塞等侍接收完整数据包,主进程/线程无法执行运算同响应其它请求,非常浪费硬件资源,解决方案是每个socket开个线程/进程独立处理
public final class ServerBio {
private static int DEFAULT_PORT = 12345;
private static ServerSocket server;
private static AtomicInteger ai = new AtomicInteger(); public static void main(String[] args) throws Exception {
try {
server = new ServerSocket(DEFAULT_PORT);
System.out.println("服务器已启动,端口号:" + DEFAULT_PORT);
while (true) {
Socket socket = server.accept();
ai.incrementAndGet();
new Thread(new ServerHandler(socket)).start();
}
} finally {
if (server != null) {
System.out.println("服务器已关闭。");
server.close();
server = null;
}
}
} public static class ServerHandler implements Runnable {
private Socket socket;
private BufferedReader in = null;
private PrintWriter out = null; public ServerHandler(Socket socket) {
this.socket = socket;
} @Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
String body;
while (true) {
if ((body = in.readLine()) == null) {
continue;
}
System.out.println("服务器收到消息:" + body);
out.println(ai.get());
}
} catch (Exception e) { } finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class ClientBio {
private static int DEFAULT_SERVER_PORT = 12345;
private static String DEFAULT_SERVER_IP = "127.0.0.1";
private static AtomicInteger ai = new AtomicInteger(); private Socket socket = null;
private BufferedReader in = null;
private PrintWriter out = null; public static void main(String[] args) throws InterruptedException {
while (true) {
send("xxxxxx");
Thread.sleep(1);
}
} public static void send(String body) {
new ClientBio().send(DEFAULT_SERVER_PORT, body);
} public void send(int port, String body) {
try {
socket = new Socket(DEFAULT_SERVER_IP, port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
out.println(body);
ai.incrementAndGet();
System.out.println("客户端 接收:" + in.readLine());
} catch (Exception e) {
e.printStackTrace();
}
}
}
BIO有个致命的缺点,由于线程/进程资源是有限的,在测试发现当开了500线程左右每接收/创建一个socket时间变得越来越长,也就是说采用BIO模型的瓶颈在500左右(大众机器)
解决方案也简单:线程是有限的,那么就用池程线来重用线程
ServerBioPool.class 只需要添加ExecutorService pool 替换掉Thread即可
private static ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*10);
public static void main(String[] args) throws Exception {
try {
server = new ServerSocket(DEFAULT_PORT);
System.out.println("服务器已启动,端口号:" + DEFAULT_PORT);
while (true) {
Socket socket = server.accept();
ai.incrementAndGet();
pool.submit(new ServerHandler(socket));
}
} finally {
// 一些必要的清理工作
if (server != null) {
System.out.println("服务器已关闭。");
server.close();
server = null;
}
}
}
上面应用场景比较有限,如果是长连接不释放socket资源的话,每个socket占用一个thread,用thread pool只能优化thread创建和销毁的频率并不能解决thread不足问题,读者可以试下把线程数改成800再测试。
现实与理想差距还是很大的
我们来论证瓶颈是否出现在线程上,屏蔽掉 ServerBioPool.class ClientBio.class 发送接收处理
public static void main(String[] args) throws Exception {
server = new ServerSocket(DEFAULT_PORT);
System.out.println("服务器已启动,端口号:" + DEFAULT_PORT);
while (true) {
Socket socket = server.accept();
ai.incrementAndGet();
System.out.println(ai.get());
}
}
ClientBio.class
public void send(int port, String body) {
try {
socket = new Socket(DEFAULT_SERVER_IP, port);
} catch (Exception e) {
e.printStackTrace();
}
}
结果打印出的数字能突破成千上万
如果client使用bio是无影响的,因为由始至终只有一个socket
小结:使用BIO模型,性能屏颈受线程/进程数上限影响,client可以使用bio
[编织消息框架][网络IO模型]BIO的更多相关文章
- [编织消息框架][网络IO模型]aio
asynchronous I/O (the POSIX aio_functions)—————异步IO模型最大的特点是 完成后发回通知. [编织消息框架][网络IO模型]NIO(select and ...
- [编织消息框架][网络IO模型]NIO(select and poll)
上面测试论证系统内核在read data时会阻塞,如果我们在把第一个阶段解决掉那么性能就会提高 NIO 编程 JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度.实 ...
- [编织消息框架][网络IO模型]Netty Reactor
严格来讲Netty Reactor是一种设计模式,一听模式两字就知道了吧,套路哈哈 Reactor中文译为“反应堆”. 看图netty处理流程 1.netty server 至少有两组reactor. ...
- 打开APP 04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋
打开APP 04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋
- Socket-IO 系列(一)Linux 网络 IO 模型
Socket-IO 系列(一)Linux 网络 IO 模型 一.基本概念 在正式开始讲 Linux IO 模型前,先介绍 5 个基本概念. 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器, ...
- 网络IO模型与Reactor模式
一.三种网络IO模型: 分类: BIO 同步的.阻塞式 IO NIO 同步的.非阻塞式 IO AIO 异步非阻塞式 IO 阻塞和同步的概念: 阻塞:若读写未完成,调用读写的线程一直等待 非阻塞:若读写 ...
- [编织消息框架][消息服务]rmi
RMI(即Remote Method Invoke 远程方法调用) 远程对象: 用于远程客户端调用 必需继承java.rmi.Remote,每个调用方法必须添加java.rmi.RemoteExcep ...
- 通过实例理解Java网络IO模型
网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的. 以 ...
- Unix 网络IO模型介绍
带着问题阅读 1.什么是同步异步.阻塞非阻塞 2.有几种IO模型,不同模型之间有什么区别 3.不同IO模型的应用场景都是什么 同步和异步.阻塞和非阻塞 同步和异步 广义上讲同步异步描述的是事件中发送方 ...
随机推荐
- linux网络编程1 最简单的socket编程
下面是socket编程的服务器端 先看一个图,1 #include<stdio.h> #include<stdlib.h> #include<string.h> # ...
- 图片流量节省大杀器:基于腾讯云CDN的sharpP自适应图片技术实践
目前移动端运营素材大部分依赖图片,基于对图片流量更少,渲染速度更快的诉求,我们推动CDN,X5内核,即通产品部共同推出了一套业务透明,无痛接入的CDN图片优化方案:基于CDN的sharpP自适应图片无 ...
- 3301: [USACO2011 Feb] Cow Line
3301: [USACO2011 Feb] Cow Line Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 82 Solved: 49[Submit ...
- Alamofire源码解读系列(六)之Task代理(TaskDelegate)
本篇介绍Task代理(TaskDelegate.swift) 前言 我相信可能有80%的同学使用AFNetworking或者Alamofire处理网络事件,并且这两个框架都提供了丰富的功能,我也相信很 ...
- Oracle数据库笔记
SQL分为四大类别 1.DDL:Date Definition Language 数据定义语言 用于建立.修改.删除数据库对象(create创建表和其它对象结构:alter修改表或其它结构:drop ...
- mybatis 使用@Select 注解,因为字符编码不一致导致mybatis 报错
使用 mybatis 的@Select 注解, @Select({ "<script>select " + ALL_COLUMNS + " from &quo ...
- NDK(三方库引入、Mk文件)
NDK笔记-----第三方库引入 一.字符操作: 1 二.NDK*(JNI)对象操作: 2 1.C++调用java对象 3 三.Android.mk说明: 3 四.Application.mk说明 3 ...
- ZJOI2017 Day3 滚粗记
私のZJOI Day3 2017-3-21 07:52:53 今天,考了人生当中的第一次省选(虽然只是普及组三等奖但仍然有幸能体会一下).据胡老师说,这就是来体验一下被大神虐--真的是这样,听课听不懂 ...
- jsp中九大内置对象
jsp实质是一个Servlet类,当jsp页面第一次被访问时,就会被服务器翻译成.java文件,紧接着就编译成.class文件. jsp<% %>和<%= %>脚本中可以直接使 ...
- c#实现list,dataset,DataTable转换成josn等各种转换方法总和
using System;using System.Collections.Generic;using System.Text;using System.Data;using System.Refle ...