在实际的工作开发中,传统的模型有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. [De1CTF 2019]Giftbox 分析&&TPOP学习

    [De1CTF 2019]Giftbox 刚进来我以为是直接给了shell,恐怖如斯. 随便扔了个命令,之后就没然后了,hhh,截包发现可能存在sql注入. 然后我就不会了... what i lea ...

  2. Java基础——HashMap

    1.HashMap底层的实现 JDK 1.7 中 HashMap 是以数组+链表的形式组成的 JDK 1.8 之后数组+链表/红黑树的组成的,当链表大于 8 并且容量大于 64 时,链表结构会转换成红 ...

  3. sqlserver date与datetime区别及sqlserver日期格式转换

    date是SQL Server 2008新引进的数据类型.它表示一个日子,不包含时间部分,可以表示的日期范围从公元元年1月1日到9999年12月31日.只需要3个字节的存储空间.DateTime 日期 ...

  4. HTML+CSS系列:登录界面实现

    一.效果 二.具体实现 1.index.html <!DOCTYPE html> <html> <head> <meta charset="utf- ...

  5. 【网络协议】TCP/IP:数据链路层

    物理层负责把计算机中的0.1数字信号转换为具体传输媒介的物理信号(电压的高低.电波的强弱.光的闪灭) 数据链路层协议定义了(通过通信介质互连的设备间的)数据传输规范 (常见的通信介质有同轴电缆.双绞线 ...

  6. ECharts系列:玩转ECharts之常用图(折线、柱状、饼状、散点、关系、树)

    一.背景 最近产品叫我做一些集团系列的统计图,包括集团组织.协作.销售.采购等方面的.作为一名后端程序员,于是趁此机会来研究研究这个库. 如果你仅仅停留在用的层面,那还是蛮简单的. 二.介绍 ECha ...

  7. SQL实战——03. 查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no

    查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_noCREATE TABLE `dept_manager` (`dept_no` char(4) ...

  8. javaFX 在窗口的标题栏显示当前时间,1秒更新一次时间

    例1:在窗口的标题栏显示当前时间,1秒更新一次时间 1 import java.text.DateFormat; 2 import java.text.SimpleDateFormat; 3 impo ...

  9. IntelliJ IDEA 调试 Java 8 Stream,实在太香了!

    前段时间,栈长发布了一篇关于 Java 8 Optional.map 的实用文章,留言区就有的人说 Java 8 的语法糖不方便调试,还要视情况使用. 留言区也有人说 IntelliJ IDEA 早已 ...

  10. 如何查找一个为NULL的MYSQL字段

    前言:在做这个题目 https://www.cnblogs.com/pipihao/p/13786304.html 因为之前 我好像没有接触过什么 为NULL字段的查询,细节不小 WHERE 字段 I ...