[编织消息框架][网络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模型的应用场景都是什么 同步和异步.阻塞和非阻塞 同步和异步 广义上讲同步异步描述的是事件中发送方 ...
随机推荐
- SpringMVC-HelloWorld (XML)
Spring2.5.6开启了Spring的注解时代,简化了的xml配置,提高了开发效率:但是,对于Spring的初学者,xml配置更容易理解的Spring的Ioc特性,aop特性:本文使用Maven构 ...
- Eclipse标准版安装J2EE插件
WTP 使用Eclipse IDE for Java EE Developers是非常方便,但是太大,我喜欢按需配置.首先我们来了解什么是WTP. WTP(Web Tools Platform )项目 ...
- J2ee技术难点
J2ee技术难点 session/cookie区别联系 jsp/servlet区别联系 filter执行流程 openSessionInView原理 clone与servilizable区别联系 eq ...
- View的呈现(一)ActionResult
ActionResult Http是一个单纯采用请求/回复消息交换模式的网络协议,Web服务器在接收并处理来自客户端的请求后悔根据处理结果对请求予以回应.一般来说针对请求的处理最终体现在对目标Acti ...
- 自定义cell设置现价,原价(加横线)
原价,现价分别是连个label.这两个label不能直接限制死他们的宽度,因为他们的宽度不确定,而由于lable的特殊性,不设置它的宽度约束时,宽度取决于文字的内容,所以两个lable的约束设置好一些 ...
- 如何理解jQuery中的ajaxSubmit方法
版权声明:本文为博主原创文章,转载请标注:www.cnblogs.com/gdsblog 刚刚学习中,使用到了ajaxSubmit,犹豫以前没有接触㢧这个,所以刚开始是一脸懵逼状态,最后通过查找资料的 ...
- 3410: [Usaco2009 Dec]Selfish Grazing 自私的食草者
3410: [Usaco2009 Dec]Selfish Grazing 自私的食草者 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 71 Solve ...
- 微信企业号接收消息(使用SpringMVC)
微信企业号接收消息(使用SpringMVC) 微信企业号接收消息(使用SpringMVC) 将应用设置在回调模式时,企业可以通过回调URL接收员工回复的消息,以及员工关注.点击菜单.上报地理位置等事件 ...
- R语言数据分析利器data.table包 —— 数据框结构处理精讲
R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理 ...
- 【树莓派】Linux自动配置IP
由于需要配置多台树莓派设备,但需要将IP配置为静态IP,而一台一台手动执行比较慢,所以写了一份脚本,sudo 执行即可. 将下面内容复制在家目录下,命名为auto.sh 然后执行 sudo sh au ...