JAVA BIO

JAVA BIO深入剖析

    • 1. Java BIO 基本介绍
    • 2. Java BIO 工作机制
    • 3. 传统BIO编程
    • 4. BIO模式下的多发和多收消息
    • 5. BIO模式下接收多个客户端
    • 6. 伪异步I/O编程
    • 7. 基于BIO的文件上传
    • 8. Java BIO模式下的端口转发
    • 9. 基于BIO模式下的即时通信
      • 功能清单简单说明
      • 项目启动与演示

1. Java BIO 基本介绍

  • Java BIO 就是传统的 java io 编程,其相关的类和接口在 java.io
  • BIO(blocking I/O) : 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需
    要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器).

2. Java BIO 工作机制

在这里插入图片描述

对 BIO 编程流程的梳理

  1. 服务器端启动一个 ServerSocket,注册端口,调用accpet方法监听客户端的Socket连接。
  2. 客户端启动 Socket 对服务器进行通信,默认情况下服务器端需要对每个客户 建立一个线程与之通讯

3. 传统BIO编程

网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信(绑定IP地址和端口),客户端通过连接操作向服务端监听的端口地址发起连接请求,基于TCP协议下进行三次握手连接,连接成功后,双方通过网络套接字(Socket)进行通信。
传统的同步阻塞模型开发中,服务端ServerSocket负责绑定IP地址,启动监听端口;客户端Socket负责发起连接操作。连接成功后,双方通过输入和输出流进行同步阻塞式通信。
基于BIO模式下的通信,客户端 - 服务端是完全同步,完全耦合的。

/**目标: Socket网络编程。Java提供了一个包:java.net下的类都是用于网络通信。Java提供了基于套接字(端口)Socket的网络通信模式,我们基于这种模式就可以直接实现TCP通信。只要用Socket通信,那么就是基于TCP可靠传输通信。功能1:客户端发送一个消息,服务端接口一个消息,通信结束!!创建客户端对象:(1)创建一个Socket的通信管道,请求与服务端的端口连接。(2)从Socket管道中得到一个字节输出流。(3)把字节流改装成自己需要的流进行数据的发送创建服务端对象:(1)注册端口(2)开始等待接收客户端的连接,得到一个端到端的Socket管道(3)从Socket管道中得到一个字节输入流。(4)把字节输入流包装成自己需要的流进行数据的读取。Socket的使用:构造器:public Socket(String host, int port)方法:  public OutputStream getOutputStream():获取字节输出流public InputStream getInputStream() :获取字节输入流ServerSocket的使用:构造器:public ServerSocket(int port)小结:通信是很严格的,对方怎么发你就怎么收,对方发多少你就只能收多少!!*/
public class Server {public static void main(String[] args){System.out.println("服务端 启动 !!!");try {//1.定义一个ServerSocket对象,进行服务端的端口注册ServerSocket serverSocket = new ServerSocket(9999);//2.监听客户端的连接请求Socket socket = serverSocket.accept();//3.从socket管道中得到字节数入流对象InputStream is = socket.getInputStream();//4.把字节输入流包装成字符输入流,再包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//5.打印接收数据String msg;while ((msg = br.readLine()) != null){System.out.println("服务端接收到:"+msg);}} catch (IOException e) {e.printStackTrace();}}
}
public class Client {public static void main(String[] args) {try {//1.创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//2.从socket中获取字节输出流OutputStream os = socket.getOutputStream();//3.把字节输出流包装成打印流PrintStream ps = new PrintStream(os);//4.向服务端发数据ps.print("hello! i am from client !"); // 没有换行符,客户端执行完socket断掉,服务端还没读取到一行,发现客户端socket断了只能抛出异常了。//ps.println("hello! i am from client !"); // 有换行符,客户端发送完socket断掉,服务器读取到一行数据,输出完正常断掉socket。ps.flush();} catch (IOException e) {e.printStackTrace();}}
}

小结

  • 在以上通信中,服务端会一致等待客户端的消息,如果客户端没有进行消息的发送,服务端将一直进入阻塞状态。
  • 同时服务端是按照行获取消息的,这意味着客户端也必须按照行进行消息的发送,否则服务端将进入等待消息的阻塞状态!

4. BIO模式下的多发和多收消息

/*** 目标:* 服务端可以反复接收消息* 客户端可以反复发送消息*/
public class Server {public static void main(String[] args){System.out.println("服务端 启动 !!!");try {//1.定义一个ServerSocket对象,进行服务端的端口注册ServerSocket serverSocket = new ServerSocket(9999);//2.监听客户端的连接请求Socket socket = serverSocket.accept();//3.从socket管道中得到字节数入流对象InputStream is = socket.getInputStream();//4.把字节输入流包装成字符输入流,再包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//5.打印接收数据String msg;while ((msg = br.readLine()) != null){System.out.println("服务端接收到:"+msg);}} catch (IOException e) {e.printStackTrace();}}
}
public class Client {public static void main(String[] args) {try {//1.创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//2.从socket中获取字节输出流OutputStream os = socket.getOutputStream();//3.把字节输出流包装成打印流PrintStream ps = new PrintStream(os);//4.向服务端发数据Scanner sc = new Scanner(System.in);while (true){System.out.print("请输入:");String msg = sc.nextLine();ps.println(msg);ps.flush();}} catch (IOException e) {e.printStackTrace();}}
}

结果:
在这里插入图片描述
在这里插入图片描述

5. BIO模式下接收多个客户端

​ 在上述的案例中,一个服务端只能接收一个客户端的通信请求,那么如果服务端需要处理很多个客户端的消息通信请求应该如何处理呢,此时我们就需要在服务端引入线程了,也就是说客户端每发起一个请求,服务端就创建一个新的线程来处理这个客户端的请求,这样就实现了一个客户端一个线程的模型,图解模式如下:
在这里插入图片描述

/*** 目标:服务端可以同时接收多个客户端的socket通信连接* 思路:服务端每接收到一个客户端socket连接请求对象之后交给一个独立的线程去处理数据交互*/
public class Server {public static void main(String[] args){System.out.println("服务端 启动 !!!");try {//1.端口注册ServerSocket serverSocket = new ServerSocket(9999);//2.不断接收客户端连接请求while (true){Socket socket = serverSocket.accept();new ServerThreadReader(socket).start();}} catch (IOException e) {e.printStackTrace();}}
}
public class ServerThreadReader extends Thread{private Socket socket;public ServerThreadReader(Socket socket){this.socket = socket;}@Overridepublic void run() {try {//3.从socket管道中得到字节数入流对象InputStream is = socket.getInputStream();//4.把字节输入流包装成字符输入流,再包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//5.打印接收数据String msg;while ((msg = br.readLine()) != null){System.out.println("服务端接收到:"+msg);}} catch (IOException e) {e.printStackTrace();}}
}

客户端同上
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
小结

  • 1.每个Socket接收到,都会创建一个线程,线程的竞争、切换上下文影响性能;
  • 2.每个线程都会占用栈空间和CPU资源;
  • 3.并不是每个socket都进行IO操作,无意义的线程处理;
  • 4.客户端的并发访问增加时。服务端将呈现1:1的线程开销,访问量越大,系统将发生线程栈溢出,线程创建失败,最终导致进程宕机或者僵死,从而不能对外提供服务。

6. 伪异步I/O编程

在上述案例中:客户端的并发访问增加时。服务端将呈现1:1的线程开销,访问量越大,系统将发生线程栈溢出,线程创建失败,最终导致进程宕机或者僵死,从而不能对外提供服务。

​接下来我们采用一个伪异步I/O的通信框架,采用线程池和任务队列实现,当客户端接入时,将客户端的Socket封装成一个Task(该任务实现java.lang.Runnable线程任务接口)交给后端的线程池中进行处理。JDK的线程池维护一个消息队列和N个活跃的线程,对消息队列中Socket任务进行处理,由于线程池可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。

​图示如下:
在这里插入图片描述

/*** 目标:服务端可以同时接收多个客户端的socket通信连接* 思路:服务端每接收到一个客户端socket连接请求对象之后交给一个独立的线程去处理数据交互*/
public class Server {public static void main(String[] args){System.out.println("服务端 启动 !!!");try {//端口注册ServerSocket serverSocket = new ServerSocket(9999);//初始化线程池对象HandlerSocketServerPool pool = new HandlerSocketServerPool(5,10);while (true){//接收客户端连接请求Socket socket = serverSocket.accept();//把socket封装成任务对象Runnable target = new ServerRunnableTarget(socket);//把任务交给线程池执行pool.execute(target);}} catch (IOException e) {e.printStackTrace();}}
}
public class HandlerSocketServerPool {//线程池对象private ExecutorService executorService;/*** 初始化线程池对象* int corePoolSize,* int maximumPoolSize,* long keepAliveTime,* TimeUnit unit,* BlockingQueue<Runnable> workQueue)*/public  HandlerSocketServerPool(int maximumPoolSize, int queueSize){executorService = new ThreadPoolExecutor(3, maximumPoolSize,120, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(queueSize));}//提交任务给队列暂存,等线程池来处理public void execute(Runnable target){executorService.execute(target);}
}
public class ServerRunnableTarget implements Runnable{private Socket socket;public  ServerRunnableTarget(Socket socket){this.socket = socket;}@Overridepublic void run() {try {//从socket管道中得到字节数入流对象InputStream is = socket.getInputStream();//把字节输入流包装成字符输入流,再包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//打印接收数据String msg;while ((msg = br.readLine()) != null){System.out.println("服务端接收到:"+msg);}} catch (IOException e) {e.printStackTrace();}}
}

客户端同上

由于核心线程数是3,所以当第四个客户端连接进去并发送消息的时候,服务器并不能开启新线程处理,而是将它放到队列中;当之前的客户端连接断开之后,就会按队列中的先后顺序去处理客户端连接。

小结

  • 伪异步io采用了线程池实现,因此避免了为每个请求创建一个独立线程造成线程资源耗尽的问题,但由于底层依然是采用的同步阻塞模型,因此无法从根本上解决问题。
  • 如果单个消息处理的缓慢,或者服务器线程池中的全部线程都被阻塞,那么后续socket的i/o消息都将在队列中排队。新的Socket请求将被拒绝,客户端会发生大量连接超时。

7. 基于BIO的文件上传

/*** 客户端:上传任意类型的文件*/
public class Client {public static void main(String[] args) {try {//1.创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//2.从socket中获取字节输出流,把字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(socket.getOutputStream());//3.把上传文件的后缀给服务器dos.writeUTF(".png");//4.把文件数据发送给服务器InputStream is = new FileInputStream("/Users/lilianyun/IdeaProjects/IOTest2/src/com/BIO/demo05/clientFile/music.png");//5.向服务端发数据byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) > 0){dos.write(buffer,0,len);}dos.flush();dos.close();} catch (IOException e) {e.printStackTrace();}}
}
/*** 服务端:接收任意类型的数据并保存到磁盘*/
public class Server {public static void main(String[] args){System.out.println("服务端 启动 !!!");try {//1.端口注册ServerSocket serverSocket = new ServerSocket(9999);//2.不断接收客户端连接请求while (true){Socket socket = serverSocket.accept();//3.交给独立线程处理与客户端的文件通信new ServerThreadReader(socket).start();}} catch (IOException e) {e.printStackTrace();}}
}
public class ServerThreadReader extends Thread{private Socket socket;public ServerThreadReader(Socket socket){this.socket = socket;}@Overridepublic void run() {try {//4.从socket管道中得到字节数入流对象,包装成数据输入流DataInputStream dis = new DataInputStream(socket.getInputStream());//5.读取客户端发来的文件类型String suffix = dis.readUTF();//6.定义字节输出管道,将客户端发来的文件写出去OutputStream os = new FileOutputStream("/Users/lilianyun/IdeaProjects/IOTest2/src/com/BIO/demo05/serverFile/"+ UUID.randomUUID().toString()+suffix);//7.从数据输入流中读取数据,写到字节输出流中去byte[] buffer = new byte[1024];int len;while((len = dis.read(buffer)) > 0){os.write(buffer,0,len);}os.close();System.out.println("文件保存成功");} catch (IOException e) {e.printStackTrace();}}
}

在这里插入图片描述
小结

  • 客户端怎么发,服务端就怎么接收

8. Java BIO模式下的端口转发

需求:一个客户端发送的消息可以发送给所有客户端接收(群聊思想)
在这里插入图片描述

9. 基于BIO模式下的即时通信

基于BIO模式下的即时通信,我们需要解决客户端到客户端的通信,也就是需要实现客户端与客户端的端口消息转发逻辑。

功能清单简单说明

  1. 客户端登陆功能
    可以启动客户端进行登录,客户端登陆只需要输入用户名和服务端ip地址即可。

  2. 在线人数实时更新
    客户端用户户登陆以后,需要同步更新所有客户端的联系人信息栏。

  3. 离线人数更新
    检测到有客户端下线后,需要同步更新所有客户端的联系人信息栏。

  4. 群聊
    任意一个客户端的消息,可以推送给当前所有客户端接收。

  5. 私聊
    可以选择某个员工,点击私聊按钮,然后发出的消息可以被该客户端单独接收。

  6. @消息
    可以选择某个员工,然后发出的消息可以@该用户,但是其他所有人都能

  7. 消息用户和消息时间点
    服务端可以实时记录该用户的消息时间点,然后进行消息的多路转发或者选择。

项目启动与演示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

速览EMNLP 2020上录取的知识图谱相关论文

文 | 泽宇源 | 知乎前不久&#xff0c;自然语言处理领域三大顶会之一的 EMNLP 2020 发布了论文录取的结果。在EMNLP 2020论文正式出版之前&#xff0c;泽宇搜集了目前Arxiv上已经发布出来的录取在EMNLP 2020上所有和知识图谱相关的论文&#xff0c;下面我们就一起来一睹为快。1…

技术动态 | 数据库研究者视角下的知识图谱研究

本文转载自公众号&#xff1a;图谱学苑 。本次讲解的是数据库领域的三大会&#xff08;SIGMOD、VLDB、ICDE&#xff09;近两年关于图数据的研究进展&#xff0c;特别是知识图谱的最新研究。知识图谱是2012年Google为改进其搜索引擎而提出的概念&#xff0c;其本质是一个描述事物…

MultiDex

原文转自&#xff1a;http://coolpers.github.io/multidex/2015/04/13/multidex.html 1.MultiDex的产生背景 当Android系统安装一个应用的时候&#xff0c;有一步是对Dex进行优化&#xff0c;这个过程有一个专门的工具来处理&#xff0c;叫DexOpt。DexOpt的执行过程是在第一次加…

PYTHON得到pdf页数、遍历当前文件夹

#第一步安装PyPDF2 pip install PyPDF2#第二步导入相应的模块 from PyPDF2 import PdfFileReader#第三步&#xff1a;定义相对应的函数 def get_num_pages(file_path):"""获取文件总页码:param file_path: 文件路径:return:"""reader PdfFileRe…

LeetCode 814. 二叉树剪枝(递归)

文章目录1. 题目2. 递归解题1. 题目 给定二叉树根结点 root &#xff0c;此外树的每个结点的值要么是 0&#xff0c;要么是 1。 返回移除了所有不包含 1 的子树的原二叉树。 把只包含0的子树删除&#xff08;断开&#xff09; 来源&#xff1a;力扣&#xff08;LeetCode&…

怎样缓解灾难性遗忘?持续学习最新综述三篇

本文转载自公众号“夕小瑶的卖萌屋”&#xff0c;专业带逛互联网算法圈的神操作 -----》我是传送门 关注后&#xff0c;回复以下口令&#xff1a; 回复【789】 &#xff1a;领取深度学习全栈手册&#xff08;含NLP、CV海量综述、必刷论文解读&#xff09; 回复【入群】&#xf…

美团点评技术年货:900+页电子书,覆盖前端、后台、大数据、算法……

新年将至&#xff0c;年味渐浓。 美团点评技术年货如期而至。 从2013年12月4日发布第一篇文章&#xff0c;一直到今天&#xff0c;美团技术团队官方博客已经走过了6个春秋。 截止目前&#xff0c;我们共发布376篇技术文章&#xff0c;微信公众号&#xff08;meituantech&#x…

论文浅尝 | 基于用户反馈的交互式自然语言回答系统提升机制

本文转载自公众号&#xff1a;图谱学苑。今天介绍的工作是An Interactive Mechanism to Improve Question Answering Systems via Feedback&#xff0c;作者&#xff1a;张欣勃&#xff0c;邹磊&#xff0c;胡森&#xff0c;被CIKM2019接收。本文是一篇与知识库自然语言问答系统…

Android控件默认风格解析之SeekBar

在我们开发的时候常常需要更改原生控件的默认效果&#xff0c;有时候某些控件改起来挺费劲的&#xff0c;比如SeekBar的背景与其ProgressBar的进度粗细或者thumb居中现实与否如果弄错&#xff0c;都是个大麻烦&#xff0c;我曾经就为thumb的居中显示问题浪费了很多很多的时间&a…

基于模板的文字识别结果结构化处理技术

原文链接&#xff1a;https://cloud.tencent.com/developer/article/1425800 嘉宾 | 向宇波编辑 | suiling来源 | AI科技大本营在线公开课出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;随着行业的发展和技术的成熟&#xff0c;文字识别&#xff08;OCR&…

LeetCode 1008. 先序遍历构造二叉树(已知先序,求二叉搜索树)

文章目录1. 题目2. 解题1. 题目 返回与给定先序遍历 preorder 相匹配的二叉搜索树&#xff08;binary search tree&#xff09;的根结点。 示例&#xff1a;输入&#xff1a;[8,5,1,7,10,12]&#xff0c;已知二叉搜索树的先序&#xff08;根左右&#xff09; 输出&#xff1a…

美团开源 Logan Web:前端日志在 Web 端的实现

1.前言 Logan 是美团点评推出的大前端日志系统&#xff0c;支持多端环境运行&#xff0c;可为客户端、Web、小程序等用户端环境提供前端日志的存储、收集、上报及分析能力&#xff0c;能够帮助开发人员快速定位并解决端上问题&#xff0c;便于及时响应用户反馈与排除异常。 201…

推荐一个快速定位深度学习代码bug的炼丹神器!

文 | McGL源 | 知乎写深度学习网络代码&#xff0c;最大的挑战之一&#xff0c;尤其对新手来说&#xff0c;就是把所有的张量维度正确对齐。如果以前就有TensorSensor这个工具&#xff0c;相信我的头发一定比现在更浓密茂盛&#xff01;TensorSensor&#xff0c;码痴教授 Teren…

研讨会 | 知识图谱引领认知智能+

本文转载自公众号&#xff1a;中国计算机学会。本论坛将于 CNCC2019 中国计算机大会第一天&#xff08;10月17日&#xff09;在苏州金鸡湖国际会议中心 A102 会议室举行&#xff0c;共邀微软、阿里巴巴、华为、小米、浙江大学、苏州大学等机构的专家与你探讨。知识图谱是一种用…

LeetCode 617. 合并二叉树

文章目录1. 题目2. 递归解题1. 题目 给定两个二叉树&#xff0c;想象当你将它们中的一个覆盖到另一个上时&#xff0c;两个二叉树的一些节点便会重叠。 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠&#xff0c;那么将他们的值相加作为节点合并后的新值&…

BIO,NIO,AIO

BIO,NIO,AIO 介绍一、背景1.1 说明1.2 通信技术整体解决的问题二、Java的I/O演进之路2.1 I/O 模型基本说明2.2 I/O模型Java BIOJava NIOJava AIO2.3 BIO、NIO、AIO 适用场景分析三、BIO,NIO,AIO总结一、背景 1.1 说明 ​ 在Java的软件设计开发中&#xff0c;通信架构是不可避…

学PyTorch还是TensorFlow?

在机器学习领域&#xff0c;面对各类复杂多变的业务问题&#xff0c;构建灵活易调整的模型是高阶机器学习工程师必备的工作能力。然而&#xff0c;许多工程师还是有一个想法上的误区&#xff0c;以为只要掌握了一种深度学习的框架就能走遍天下了。事实上&#xff0c;在机器学习…

Bifrost微前端框架及其在美团闪购中的实践

Bifrost&#xff08;英 [‘bi:frɔst]&#xff09;原意彩虹桥&#xff0c;北欧神话中是连通天地的一条通道。而在漫威电影《雷神》中&#xff0c;Bifrost是神域——阿斯加德&#xff08;Asgard&#xff09;的出入口&#xff0c;神域的人通过它自由穿梭于“九界”&#xff08;指…

设计模式之观察者模式在Listview中的应用

有时候我们会有这么一个需求&#xff0c;在Listview的某个Item上有个按钮&#xff0c;点击这个按钮之后呢&#xff0c;需要对其它的item做一些操作&#xff0c;就像下面这个&#xff1a; 采纳按钮点击之前&#xff1a;采纳按钮点击之后&#xff1a; 简单介绍一下这两张图的意…

新书速递 | 《知识图谱:方法、实践与应用》

本文转载自公众号&#xff1a;博文视点Broadview 。互联网促成了大数据的集聚&#xff0c;大数据进而促进了人工智能算法的进步。近年来知识图谱作为AI领域底层技术被越来越多的人谈起。知识图谱的升温得益于新数据和新算法为规模化知识图谱构建提供了新的技术基础和发展条件&a…