在实际的工作开发中,传统的模型有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. python os模块方法详解

    os.access() 方法使用当前的uid/gid尝试访问路径.大部分操作使用有效的 uid/gid, 因此运行环境可以在 suid/sgid 环境尝试. 实例: os.chdir() 方法用于改变 ...

  2. luogu 3376 最小费用最大流 模板

    类似EK算法,只是将bfs改成spfa,求最小花费. 为什么可以呢,加入1-3-7是一条路,求出一个流量为40,那么40*f[1]+40*f[2]+40*f[3],f[1]是第一条路的单位费用,f[2 ...

  3. 微服务实战系列(八)-网关springcloud gateway自定义规则

    1. 场景描述 先说明下项目中使用的网关是:springcloud gateway, 因需要给各个网关服务系统提供自定义配置路由规则,实时生效,不用重启网关(重启风险大),目前已实现:动态加载自定义路 ...

  4. 基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中。

    react-amap 这是一个基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中. 文档实例预览: Github Web | Gitee Web 特性 ️ 自动加载高德地 ...

  5. 第一个随笔 Just For Test, Nothing Else

    第一个随笔 Just For Test, Nothing Else 注册了第一个博客,希望以后能添加点什么吧

  6. IOS 数据储存

    IOS 数据存储 ios数据存储包括以下几种存储机制: 属性列表 对象归档 SQLite3 CoreData AppSettings 普通文件存储 1.属性列表 // //  Persistence1 ...

  7. C1853 编译器错误:fatal error C1853: 'pjtname.pch' precompiled header file is from a previous

    转载:https://www.cnblogs.com/emanlee/archive/2010/10/16/1852998.html 用VC++ 2008 编写C语言程序,编译出现错误: 预编译头文件 ...

  8. matlab中colormap

    来源:https://ww2.mathworks.cn/help/matlab/ref/colormap.html?searchHighlight=colormap&s_tid=doc_src ...

  9. PHP的学习(提前学习了,业余爱好) (一)

    一个函数一个函数地堆 strstr()函数 在本地测试的时候,代码与显示如下 1.代码: <?php echo strstr("I love Shanghai!123",&q ...

  10. Github个人首页美化指北

    当你尝试去创建一个与你Github用户名相同的仓库时,会发现这是Github为你预留的特殊仓库,用来作为你的Github Profile,这个仓库就相当于一个可以显示在你Github个人页的READM ...