热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Java高级工程师蜕变之路】031RPC架构设计及IO模型

本文阐述了socket编程、IO网络模型,以及各种IO模型的适用场景。RPC架构设计文章更新历史20220301初稿。20220504修改相关描述。sock

【Java高级工程师蜕变之路】031 RPC架构设计及IO模型

本文阐述了socket编程、IO网络模型,以及各种IO模型的适用场景。

RPC架构设计

文章更新历史

2022/03/01 初稿。

2022/05/04 修改相关描述。

socket

socket网络编程

socket概述

socket套接字是两台主机之间逻辑连接的端点。

TCP/IP协议是传输层协议,主要解决数据在网络中的传输

socket是网络通信之间的抽象接口,它包含网络通信的五种基础信息:连接使用的协议、本地主机的ip地址、本地进程协议端口、远程主机ip地址、远程进程的协议端口

socket整体流程

socket编程主要包括客户端和服务端两个方面。

首先在服务端创建一个服务端套接字(ServerSocket),并把它附加到一个端口上,服务端从这个端口监听链接。

端口范围是 0-65536 ,注意 0-1024 是特权服务保留的端口。可选择任意一个不被其他进程使用的端口。

客户端请求与服务端连接时,根据服务端的域名或者ip地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的操作可以像输入输出流一样操作。

image-20220417134215803

代码实现

  1. 服务端代码

    /**
     * 服务端
     *
     * @name: ServerDemo
     * @author: terwer
     * @date: 2022-04-17 14:20
     **/
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 1.创建一个线程池,如果有客户端链接就创建一个线程与之通信
            ExecutorService executorService = Executors.newCachedThreadPool();
            // 2.创建ServerSocket
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务器已启动");
            while (true) {
                // 3.监听客户端
                Socket socket = serverSocket.accept();
                System.out.println("有客户端链接");
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        handle(socket);
                    }
                });
            }
        }
    
        private static void handle(Socket socket) {
            try {
                System.out.println("线程ID:" + Thread.currentThread().getId() + ",线程名称:" + Thread.currentThread().getName());
                // 从连接中取出输入流
                InputStream inputStream = socket.getInputStream();
                byte[] b = new byte[1024];
                int read = inputStream.read(b);
                System.out.println("客户端" + new String(b, 0, read));
    
                // 链接中取出输出流并回话
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("没有".getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  2. 客户端代码

    /**
     * 客户端
     *
     * @name: ClientDemo
     * @author: terwer
     * @date: 2022-04-17 15:30
     **/
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            while (true) {
                // 1.创建客户端socket
                Socket s = new Socket("127.0.0.1", 9999);
                // 2.从连接中获取输出流并发送消息
                OutputStream os = s.getOutputStream();
                System.out.println("请输入:");
                Scanner sc = new Scanner(System.in);
                String msg = sc.nextLine();
                os.write(msg.getBytes());
    
                // 3.从连接中取出输入流并接受会话
                InputStream is = s.getInputStream();
                byte[] b = new byte[1024];
                // 下面写法错了
                // int read = is.read();
                // 应该是
                int read = is.read(b);
                System.out.println("老板说:" + new String(b, 0, read).trim());
    
                s.close();
            }
        }
    }
    

IO模型

IO模型说明

  1. 简单理解:用什么样的通道进行数据的发送和接收。在很大程度上决定了程序通信的性能。

  2. Java支持三种网络编程模型I/O模式:BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)

    阻塞与非阻塞

    指的是网络IO的线程是否处于阻塞或者等待状态

    线程访问资源,该资源是否准备就绪的一种处理方式

    image-20220417214737992

    同步和异步

    指的是数据的请求方式,同步和异步是请求数据的一种方式。

    image-20220417215010935

BIO(同步阻塞)

Java BIO就是传统的socket编程

BIO(blocking IO):同步阻塞,服务器实现方式为一个链接一个线程,即客户端有一个链接时,服务端就要启动一个线程进行处理,如果这个链接不作任何事情,会造成不必要的线程开销,可以通过线程池改善,实现多个客户端链接服务器。

工作机制

image-20220417230159590

生活中的例子:

image-20220417230242089

BIO的问题分析
  1. 每个请求都要创建独立的线程,与对应的客户端进行read,业务处理,数据write
  2. 并发量大的时候,需要创建大量的线程来处理链接,系统资源占用较大
  3. 链接建立后,如果当前线程没有数据可读,线程就阻塞在read上,造成线程资源浪费

NIO(同步非阻塞)

同步非阻塞,服务器实现模式为一个线程处理多个请求(链接),客户端发送的链接请求会注册到多路复用器上,多路复用器轮训到链接有IO请求就进行处理。

image-20220418134554952

生活中的例子:

image-20220418134644973

AIO(异步非阻塞)

AIO引入了异步通道的概念,采用了Proactor模式,简化了程序编写,有效的请求才启动线程。

他的特点是先由操作系统完成后才通知服务端启动线程去处理,一般适用于连接数较多且连接时间较长的应用。

Proactor模式是一个消息异步通知的模式,Proactor通知的不是就绪事件,而是操作完成事件,这也是操作系统异步IO的主要模型。

https://www.zhihu.com/question/26943938

生活中的例子:

image-20220418135022363

BIO、NIO、AIO的适用场景分析

  1. BIO(同步阻塞模式)适用于连接数比较小,且固定的架构。对服务器资源的要求比较高,并发局限于应用中,jdk1.4以前的唯一选择,代码容易理解。
  2. NIO(同步非阻塞模式)适用于链接数目多且链接比较短(轻操作)的架构,比如聊天服务器、弹幕系统、服务器之间的通讯等。编程比较复杂,jdk1.4开始支持。
  3. AIO(异步非阻塞模式)适用于连接数目比较多并且连接时间比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作。编程比较复杂,jdk1.7开始支持。

推荐阅读
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 本文整理了Java中com.evernote.android.job.JobRequest.getTransientExtras()方法的一些代码示例,展示了 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
author-avatar
一枝草一滴露的执着
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有