在实际的工作开发中,传统的模型有client/service模型。client端和service端要进行通信的话,有一种套接字的方式。传统的socket编程,包含一个socket服务端和一到多个socket客户端。在连接过程中,sokcetServer 绑定一个端口进行监听。client端通过ip地址和端口号对服务进行访问。在服务进入到service端后,service端新建一个线程。线程对请求进行相应的处理,处理完毕后,将处理结果返回给client端。在处理过程中,连接client阻塞。

  代码实现:

  server端代码:

  Server 类

  ServerHandler类,业务处理类

  client端代码:

  Client类

  优点:传统的BIO模型进行通信,代码可读性比较强,理解容易。运行中,server端通过主线程监听accpet()方法阻塞式获取server的消息。

  缺点:该模型最大的问题是,每一个client端访问都对应一个后台的线程,使得系统不具备弹性伸缩能力。一旦client请求过多,线程数会迅速膨胀,系统性能会急剧下降,导致堆栈溢出,进程宕机等问题的发生。

  为了改进线程数过多,导致系统宕机的问题,同时也为了解决创建线程的消耗问题。后来又演进出了一种通过线程池或者消息队列实现1个或者多个线程处理N个客户端的模型,由于它的底层通信机制依然使用同步阻塞IO,所以被称为 “伪异步”。其原理就是在原来的service上新增一个线程池,将处理业务的线程通过线程池进行管理。如果线程数量到达上限时,将请求先存入queue中进行缓冲。具体代码如下:

  client端代码不变。

  server端:  

 1 import java.io.BufferedReader;
2 import java.io.PrintWriter;
3 import java.net.ServerSocket;
4 import java.net.Socket;
5
6 public class Server {
7
8 final static int PORT = 8765;
9
10 public static void main(String[] args) {
11 ServerSocket server = null;
12 BufferedReader in = null;
13 PrintWriter out = null;
14 try {
15 server = new ServerSocket(PORT);
16 System.out.println("server start");
17 Socket socket = null;
18 HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 50);
19 while(true){
20 socket = server.accept();
21
22 executorPool.execute(new ServerHandler(socket));
23
24 }
25
26 } catch (Exception e) {
27 e.printStackTrace();
28 } finally {
29 if(in != null){
30 try {
31 in.close();
32 } catch (Exception e1) {
33 e1.printStackTrace();
34 }
35 }
36 if(out != null){
37 try {
38 out.close();
39 } catch (Exception e2) {
40 e2.printStackTrace();
41 }
42 }
43 if(server != null){
44 try {
45 server.close();
46 } catch (Exception e3) {
47 e3.printStackTrace();
48 }
49 }
50 server = null;
51 }
52
53
54
55 }
56
57
58 }

Server类

 1 import java.util.concurrent.ArrayBlockingQueue;
2 import java.util.concurrent.ThreadPoolExecutor;
3 import java.util.concurrent.TimeUnit;
4
5
6 public class HandlerExecutorPool {
7 private ArrayBlockingQueue queue ;
8 private ThreadPoolExecutor executor;
9 public HandlerExecutorPool(int maxPoolSize, int queueSize){
10 queue = new ArrayBlockingQueue<Runnable>(queueSize);
11 this.executor = new ThreadPoolExecutor(
12 5,
13 maxPoolSize,
14 120L,
15 TimeUnit.SECONDS,
16 queue);
17 }
18
19 public void execute(Runnable task){
20 System.out.println("corePoolSize== "+executor.getCorePoolSize());
21 System.out.println("queuesize=="+queue.size());
22 this.executor.execute(task);
23
24 System.out.println("当前运行线程== "+executor.getLargestPoolSize());
25 System.out.println("queuesize=="+queue.size());
26 }
27
28
29
30 }

HandlerExecutorPool 线程池缓冲队列类

 1 import java.io.BufferedReader;
2 import java.io.InputStreamReader;
3 import java.io.PrintWriter;
4 import java.net.Socket;
5 import java.util.concurrent.TimeUnit;
6
7 public class ServerHandler implements Runnable {
8
9 private Socket socket;
10 public ServerHandler (Socket socket){
11 this.socket = socket;
12 }
13
14 @Override
15 public void run() {
16 BufferedReader in = null;
17 PrintWriter out = null;
18 try {
19 Thread.currentThread().sleep(1000);
20 in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
21 out = new PrintWriter(this.socket.getOutputStream(), true);
22 String body = null;
23 while(true){
24 body = in.readLine();
25 if(body == null) break;
26 System.out.println("Server:" + body);
27 out.println("Server response");
28 }
29 } catch (Exception e) {
30 e.printStackTrace();
31 } finally {
32 if(in != null){
33 try {
34 in.close();
35 } catch (Exception e1) {
36 e1.printStackTrace();
37 }
38 }
39 if(out != null){
40 try {
41 out.close();
42 } catch (Exception e2) {
43 e2.printStackTrace();
44 }
45 }
46 if(socket != null){
47 try {
48 socket.close();
49 } catch (Exception e3) {
50 e3.printStackTrace();
51 }
52 }
53 socket = null;
54 }
55
56
57 }
58
59 }

ServerHandler类,业务处理类

  这样改造后,有效的缓解了server端线程数过多时宕机的问题,但是依然没有解决阻塞的问题。依然会出现请求过多时,前台等待超时的问题。

BIO编程的更多相关文章

  1. Java IO编程全解(二)——传统的BIO编程

    前面讲到:Java IO编程全解(一)——Java的I/O演进之路 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口 ...

  2. 深入学习Netty(1)——传统BIO编程

    前言 之前看过Dubbo源码,Nacos等源码都涉及到了Netty,虽然遇到的时候查查资料,后面自己也有私下学习Netty并实践,但始终没有形成良好的知识体系,Netty对想要在Java开发上不断深入 ...

  3. JDK BIO编程

    网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建 ...

  4. netty学习(二)--传统的bio编程

    网络编程的基本模型是Client/Server模型.也就是两个进程之间进行相互通信,当中服务端提供位置信息( 绑定ip地址和监听port),client通过连接操作向服务端监听的地址发送连接请求,通过 ...

  5. bio编程示例

    直接干代码,用BIO写一个Server端,然后使用telnet模拟客户端发送数据 import java.io.IOException; import java.io.InputStream; imp ...

  6. (转)Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    原文出自:http://blog.csdn.net/anxpp/article/details/51512200 1.BIO编程 1.1.传统的BIO编程 网络编程的基本模型是C/S模型,即两个进程间 ...

  7. Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...

  8. io编程,bio,nio,aio

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...

  9. hadoop---Java 网络IO编程总结BIO、NIO、AIO

    转载请注明出处:http://blog.csdn.net/anxpp/article/details/51512200,谢谢! 本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解 ...

随机推荐

  1. burp suite之Target(目标)

    Target : 将攻击的目标,全部展现到Target下. Site map:站点地图 Scope: 范围 目录爬行: 复制所有子目录的链接 Spidor this host: 发送至Spidor选项 ...

  2. 高德AR & 车道级导航技术演进与实践

    2020云栖大会于9月17日-18日在线上举行,阿里巴巴高德地图携手合作伙伴精心组织了"智慧出行"专场,为大家分享高德地图在打造基于DT+AI和全面上云架构下的新一代出行生活服务平 ...

  3. Python+selenium+unittest实现网址登陆及页面跳转校验

    这个网址登陆的单元测试代码都写在一个文件中,方便初学者查看和调试:实际测试工作中根据情况进行模块化处理. 话不多说,分布上代码 一.import必要模块 二.创建测试类,初始化测试环境 三.定义登陆方 ...

  4. springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面

    测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...

  5. 如何高雅的使用redis去获取一个值

    //场景,给定一个订单号来从缓存中查询一个订单信息; 步骤: 1从redis中直接获取,有数据就返回 2.如果redis中没有值,就查数据库 3.数据库查到的数据不为空,就刷到redis中 4.返回查 ...

  6. Redis小记(二)

    1.redis数据库 redis数据库属于内存数据库,若不将数据存到磁盘中,服务器进程退出,数据也会消失 redis所有数据库都保存在redisServer结构的db数组中,db数组的每一项都是一个r ...

  7. Centos-删除文件或目录-rm

    rm 删除目录或者文件,如果是链接文件,则只删除这个链接文件而不是链接指向的文件 相关选项 -r 递归删除目录 -f 忽略不存在提示和确认提示,本身确认提示系统默认添加-i参数 -i 删除文件前提示, ...

  8. Spring Boot入门系列(二十)快速打造Restful API 接口

    spring boot入门系列文章已经写到第二十篇,前面我们讲了spring boot的基础入门的内容,也介绍了spring boot 整合mybatis,整合redis.整合Thymeleaf 模板 ...

  9. [HAOI 2017]八纵八横

    线段树分治+线形基. 线段树分治是个锤子?? 以时间轴构建线段树,把每个环以"对线段树产生影响的时间区间"的形式加入线段树即可. #include<bits/stdc++.h ...

  10. xshell选项卡不见了

    最近使用xshell的时候发现建立多个选项卡的时候,因为没有选项卡,所以不能切换. 弄了好一会儿才弄出来 点击会话选项卡或者Ctrl + Shift + T可以调出来