浅谈java网络编程及RPC框架

news2025/1/18 20:16:40

目录

1.计算机网络

2.TCP/IP协议

3.UDP协议

4.RPC框架


1.计算机网络

从资源共享的角度上来说,计算机网络就是以能够相互共享资源的方式互连起来的自治计算机系统的集合。网络建立的主要目的是实现计算机资源的共享。

目前来说,计算机网络分为两大模型:OSI 7层模型 及 TCP/IP 4层模型,相互之间的对应关系如下:

  1. 应用层:网络服务与最终用户的一个接口
  2. 表示层:数据的表示、安全、压缩
  3. 会话层:建立、管理、中止会话
  4. 传输层:定义传输数据的协议端口号,以及流控和差错校验
  5. 网络层:进行逻辑地址寻址,实现不同网络之间的路径选择
  6. 数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能
  7. 物理层:建立、维护、断开物理连接

目前来说,OSI七层模型只是理论上的理想模型,并没有实现;TCP/IP模型是应用更广泛的计算机网络模型。

 每一层使用的协议如下:

OSI模型TCP/IP模型协议
应用层应用层HHTP、FTP、SMTP、Telnet、DNS等
表示层
会话层
传输层传输层TCP、UDP
网络层网络层IP、ARP、RARP等
数据链路层网络接口层IEEE802.1A、802.2等
物理层

在计算机网络中,我们可以通过IP定位唯一一部主机,java网络编程就是在次基础上,主要依靠的是传输层的协议进行网络通信,使用的TCP/IP模型。

2.TCP/IP协议

TCP :传输控制协议 ,是可靠的协议 (安全性高,速度慢)。

即TCP协议需要通信双方建立连接才可以进行通信;当通信结束后,则关闭连接。

三次握手(建立连接):

  1. 第一次握手:客户端发送连接请求(SYN报文,将seq置为x),发送完毕后客户端进入SYN_SEND(同步已发送)状态。
  2. 第二次握手: 服务器收到SYN报文,向客户端发送SYN+ACK报文, seq置为y,ack置为x+1(sea值+1)。发送后客户端进入SYN_RCVD状态
  3. 第三次握手:客户端收到SYN+ACK报文后,明白两方收发都没有问题。但还需要向服务器发送ACK报文,ack置为y+1,seq置为x+1。

客户端与服务端建立连接后,即可进行数据通信。

四次挥手(关闭连接):

  1. 第一次挥手:客户端发送连接释放报文,并停止再发送数据,主动关闭TCP连接。 FIN=1,seq=u 发送完后进入FIN-WAIT-1 状态
  2. 第二次挥手:服务器接收到后发出确认,ACK=1,seq=v,ack=u+1然后进入CLOSE_WAIT状态。
  3. 第三次挥手:数据传输完后,服务器发出连接释放的报文。FIN=1,ACK=1,seq=w,ack=u+1, 发送完后进入LAST-ACK(最后确认)状态。
  4. 第四次挥手:客户端收到后,将发出确认,ACK=1,ack=w+1,seq=u+1,发送完后将进入TIME-WAIT状态

TCP/IP只是一个协议栈,就像操作系统的运行机制一样,需要具体的实现,同时还要提供对外的编程接口,这个接口就是Socket 。

java网络编程也是通过Socket类进行实现:

(1)TCP服务端:

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

//tcp服务端
class TCPServer {

    public static void main(String[] args) {
        //创建TCP服务端,开放8080端口供客户端连接
        TCPServer server = new TCPServer(8080);
        //监听消息
        server.getFile();
    }

    private ServerSocket serverSocket;
    //构造方法,建立连接
    //阻塞式连接,即运行后不会停止,直至客户端连接调用逻辑后关闭连接
    public TCPServer(int port) {
        try {
            this.serverSocket = new ServerSocket(port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //接受客户端发送的字符
    public void getMessage() {
        Socket accept = null;
        InputStream inputStream = null;
        ByteOutputStream outputStream = null;
        try {
            while (true) {
                //2.监听消息,等待客户端连接
                accept = this.serverSocket.accept();
                //3.读取客户端消息
                inputStream = accept.getInputStream();

                outputStream = new ByteOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, len);
                }
                System.out.println("收到消息:" + outputStream.toString());
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭流
                assert outputStream != null;
                outputStream.close();
                inputStream.close();
                accept.close();
                serverSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    //接受客户端发送的文件流
    public void getFile(){
        try {
            //2.监听消息,等待客户端连接
            Socket accept = this.serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(new File("accept.jpg"));
            byte[] bytes = new byte[1024];
            int len;
            while ((len=inputStream.read(bytes))!=-1){
                fileOutputStream.write(bytes,0,len);
            }

            fileOutputStream.close();
            inputStream.close();
            accept.close();
            this.serverSocket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

(2)TCP客户端:

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

//TCP客户端
class TCPClient{

    public static void main(String[] args) {
        //发送消息
        TCPClient client = new TCPClient("127.0.0.1",8080);
        client.sendFile();
    }

    private Socket socket;
    public TCPClient(String ip, int port){
        try{
            //1.获取服务端地址
            InetAddress inetAddress = InetAddress.getByName(ip);
            //2.创建连接
            this.socket = new Socket(inetAddress,port);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void sendMessage() {
        try{
            //3.发送消息
            OutputStream outputStream = this.socket.getOutputStream();
            outputStream.write("测试消息".getBytes(StandardCharsets.UTF_8));
            //4.关闭流
            outputStream.close();
            this.socket.close();

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void sendFile(){
        try {
            OutputStream os = this.socket.getOutputStream();
            FileInputStream fis = new FileInputStream(
                    new File("你的文件路径"));
            byte[] buffer = new byte[1024];
            int len;
            while ((len=fis.read(buffer))!=-1){
                os.write(buffer,0,len);
            }
            //文件传输完,告诉服务端
            socket.shutdownOutput();
            //关闭流
            fis.close();
            os.close();
            this.socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

}

3.UDP协议

UDP:用户数据报协议 ,是不可靠的协议(安全性不高,速度快.

UDP是不可靠的传输协议,即双方不需要建立连接,更类似于短信通信。

(1)服务端(接受):

public class TalkReceive implements Runnable{

    private DatagramSocket socket = null;
    private int port;
    private String msgFrom;

    public TalkReceive(int port, String msgFrom){
        this.port=port;
        this.msgFrom=msgFrom;
        try {
            socket = new DatagramSocket(port);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            while (true){
                //接收数据,阻塞式接受
                byte[] buffer = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                socket.receive(packet);

                System.out.println(msgFrom+":"+
                        new String(packet.getData(),0, packet.getLength()));

                //bye,退出循环
                if ("bye".equals(new String(buffer,0, packet.getLength()))){
                    break;
                }

            }
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

(2)客户端(发送):

public class TalkSender implements Runnable{
    //1.建立socket
    private DatagramSocket socket = null;
    private final String toIp;
    private final int toPort;

    public TalkSender(int fromPort, String toIp, int toPort){
        this.toIp=toIp;
        this.toPort=toPort;
        try{
            socket=new DatagramSocket(fromPort);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        while (true) {
            //2.建立包
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String message = null;
            try {
                while(true){
                    message = reader.readLine();
                    //参数:发送体,发送起始长度,结束长度,目标地址,端口号
                    DatagramPacket packet = new DatagramPacket(message.getBytes(StandardCharsets.UTF_8),
                            0, message.getBytes(StandardCharsets.UTF_8).length,
                            new InetSocketAddress(this.toIp,this.toPort));
                    //发送
                    socket.send(packet);

                    if ("bye".equals(message)){
                        break;
                    }
                }

                socket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

(3)实现通信:

public class teacher {
    public static void main(String[] args) {
        new Thread(new TalkSender(5555,"127.0.0.1",8888)).start();
        new Thread(new TalkReceive(7777,"student")).start();
    }
}
public class student {
    public static void main(String[] args) {
        new Thread(new TalkSender(6666,"127.0.0.1",7777)).start();
        new Thread(new TalkReceive(8888,"teacher")).start();
    }
}

即可实现双方通信聊天。

4.RPC框架

是什么:RPC(Remote Procedure Call)即远程过程调用。区别于本地调用,RPC是指调用远端机器(或是其他微服务)的方法,且不需要关心底层的调用细节,如网络协议和传输协议等,只需要关注调用方法的参数。

为什么需要

随着业务的发展,服务功能持续迭代,单体应用出现性能瓶颈,因此需要考虑对服务进行拆分,根据业务功能划分为不同的模块,这就是微服务。

不同的微服务之间不是毫无关系的,微服务整体构成一个系统,所以相互之间需要进行通信完成功能,保证服务的整体性能。一个服务拆分为不同的模块,或者单体应用拆分为多个微服务时,此时便需要RPC出场了,不同模块及不同服务间都需要RPC才能完成通信。

而基于Restful的远程过程调用也可实现以上功能,但由于Restful主要基于HTTP,封装的数据量更多所以数据传输量更大效率比较低,因此RPC被提出了。

可以说RPC是分布式系统架构或者微服务架构必不可少的实现手段。

怎么实现:

实现RPC首先需要服务注册发现:由于调用的是远端对象,因此需要可以定位到调用的服务器地址以及调用的具体方法的进程,常用的服务注册中心有zookeeper、nacos等。

同时,网络传输的是二进制数据,RPC需要支持将函数参数(如基本类型int、long、map以及自定义类型等)等传输至远程方法才可以进行调用,所以需要对其进行序列化及反序列化,保证传输参数及返回结果的可用性及可读性。

最后,RPC的核心在于网络通信,它主要是基于TCP协议进行实现的。


 

 

如上图所示,一个完整的RPC架构主要分为三个部分:客户端(调用者)、服务注册中心、服务端(被调用者),一次调用的过程一般如下:

  1. 服务端通过服务注册中心进行注册,暴露自身。
  2. 客户端发起远程调用,通过服务发现到服务注册中心找到对应的调用服务地址,然后根据RPC协议创立TCP连接,发起远程调用。
  3. 调用成功后,得到返回结果,关闭连接,调用结束。

所以,一个完整的商用 RPC 框架最核心的基本就是三个:服务寻址数据编码网络传输。

常用的RPC框架:

(1)gRPC

gRPC是一个高性能、通用的开源RPC框架,其由Google2015年主要面向移动应用开发并基于HTTP/2标准协议而设计,基于ProtoBuf序列化协议开发,且支持众多语言开发。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链式功能,从而有助于节省带宽、降低TCP连接次数、节省CPU使用、电池寿命。


(2)Dubbo

Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用,目前Dubbo已经交给Apache基金会维护。

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

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

相关文章

JRE和JDK 及 常用DOS命令

JRE和JDK Java程序开发的三个步骤 ●编写代码 ●编译代码 ●运行代码 1.编写代码 A.txt JRE : JRE是Java Runtime Environment缩写,指Java运行环境,包含JVM虚拟机及Java核心类库。 类:java文件在代码中的集合体现( 类java文件&#xf…

CAD转SHP最好的方法 赶快收藏起来吧

1、利用 ArcToolsbox 工具先将 DWG 文件转为 MDB 通过 CASS 软件生成的 DWG 文件,字段中包含有很多属性内容,所以我们先将 DWG 格式 的文件转换为 MDB 格式,再通过 MDB 转换为 SHP 格式数据进行整理。具体步骤如下: 通过 ArcTool…

jenkins——凭据管理

这里写目录标题 一、Jenkins 凭据管理1、凭据管理入口2、凭据的新增3、用户名和密码方式的凭据配置4、SSH密钥方式的凭据配置5、凭据的更新和删除6、凭据的使用 一、Jenkins 凭据管理 凭据管理的作用:管理ssh、邮箱、git等认证信息 1、凭据管理入口 Dashboard —…

深度学习实战24-人工智能(Pytorch)搭建transformer模型,真正跑通transformer模型,深刻了解transformer的架构

大家好,我是微学AI,今天给大家讲述一下人工智能(Pytorch)搭建transformer模型,手动搭建transformer模型,我们知道transformer模型是相对复杂的模型,它是一种利用自注意力机制进行序列建模的深度学习模型。相较于 RNN 和…

【微信小程序】数据监听器,纯数据字段

一、数据监听器 1.1 什么是数据监听器 数据监听器用于 监听和响应任何属性和数据字段的变化,从而执行特定的操作 。它的作用类似于 vue 中 的 watch 侦听器。在小程序组件中, 在componets中新建一个test2文件夹在文件夹里新建component 在app.json …

C学习笔记3

1、将一个整数转换成二进制形式,就是其原码。(通俗的理解,原码就是一个整数本来的二进制形式。) 例如short a 6;a 的原码就是0000 0000 0000 0110 2、反码就区分正负数,因为正负数的反码是不一样的,正数…

2023年MathorCup数模D题赛题解题思路

MathorCup俗称妈杯,是除了美赛国赛外参赛人数首屈一指的比赛,而我们的妈杯今天也如期开赛。今年的妈杯难度,至少在我看来应该是2023年截至目前来讲最难的一场比赛。问题的设置、背景的选取等各个方面都吐露着我要难死你们的想法。难度是恒定的…

Euro-NCAP 2030愿景

每隔五年,Euro NCAP都会将利益相关者聚集在一起,研究当前的汽车技术现状,预测未来几年可能的挑战,并确定未来的机会所在。讨论的结果是该组织的未来发展方向和明确的未来愿景:Euro NCAP 2030年愿景。 2020年初,Euro NCAP开始制定一套新的战略目标,打算在下一年公布其《2…

STM-32:SPI通信协议/W25Q64简介—软件SPI读写W25Q64

目录 一、SPI简介1.1电路模式1.2通信原理1.3SPI时序基本单元1.3.1起始和终止1.3.2交换字节 二、W25Q642.1W25Q64简介2.2W25Q64硬件电路2.3W25Q64框图2.4Flash操作注意事项 三、软件SPI读写W25Q643.1接线图3.2程序代码 一、SPI简介 SPI是串行外设接口(Serial Periph…

Spring Boot异步任务、异步消息

目录 1.异步任务 1.1.概述 1.2.使用 2.异步消息 2.1.概述 2.2.使用 1.异步任务 1.1.概述 举一个例子,我现在有一个网上商城,客户在界面点击下单后,后台需要完成两步: 1.创建客户订单 2.发短信通知客户订单号 这里面第2…

selenium 连接已经打开的chrome浏览器 MAC

selenium 连接已经打开的chrome浏览器 MAC 一,前言 今天在爬取chatGPT的谷歌插件的prompts的时候,发现绕不过他的反爬机制,失败111,所以想用连接已打开的chatGPT页面进行控制 二,具体步骤 1,添加环境变…

Android入门

一、Android系统架构 Android大致可以分为4层架构:Linux内核层、系统运行库层、应用框架层和应用层 1.1Linux内核层 Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了如显示、音频、照相机、蓝牙、Wi-Fi等底层的驱动。 1.2系统运行层…

2023MathorCup 高校数学建模挑战赛D题思路解析

如下为MathorCup 高校数学建模挑战赛D题思路解析: D 题 航空安全风险分析和飞行技术评估问题 飞行安全是民航运输业赖以生存和发展的基础。随着我国民航业的快速发展,针对飞行安全问题的研究显得越来越重要。2022 年 3 月 21 日,“3.21”空难…

如何使用vim的插件Ctags查看Linux源码

一.ubuntu下安装Linux内核源码 (1).查看自己的内核版本 (2).查看源内的内核源码类表 (3).下载源码 (4).进入/usr/src (5).解压下载的文件到用户主 二.安装vim插件Ctags和使用 插件的介绍 Ctags工具是用来遍历源代码文件生成tags文件,这些tags文件能被编辑器或其它工…

2023年的深度学习入门指南(4) - 在你的电脑上运行大模型

2023年的深度学习入门指南(4) - 在你的电脑上运行大模型 上一篇我们介绍了大模型的基础,自注意力机制以及其实现Transformer模块。因为Transformer被PyTorch和TensorFlow等框架所支持,所以我们只要能够配置好框架的GPU或者其他加速硬件的支持&#xff0…

同为科技(TOWE)防雷科普篇1—雷电灾害认识与雷电预警信号解读

前 言 雷电是自然界最为壮观的大气现象之一。其强大的电流、炙热的高温、猛烈的冲击波以及强烈的电磁辐射等物理效应能够在瞬间产生巨大的破坏作用,常常导致人员伤亡,击毁建筑物、供配电系统、通信设备,造成计算机信息系统中断,引…

电风扇出口欧美CE/UL507认证办理

电风扇简称电扇,是一种利用电动机驱动扇叶旋转,来达到使空气加速流通的家用电器,主要用于清凉解暑和流通空气。风扇主要由扇头、叶片、网罩和控制装置等部件组成。电风扇的主要部件是:交流电动机。其工作原理是:通电线圈在磁场中受力而转动。…

Streamlit 中函数多次进入的问题

Streamlit 函数多次进入的问题 Streamlit 学习的背景重要案例心得踩坑或注意点 Streamlit 学习的背景 最近在学习ai相关的知识,同时需要做一些方便使用的web网页。 例如:调用chatGPT的api,做对话窗。 之前用过gradio, 但是发现在手机端上&am…

NestJS:理解ORM(Object Relational Mapping)

一、理解ORM(Object Relation Mapping) ORM是对象—关系映射(Object/Relation Mapping,ORM)是为了解决面向对象与关系数据库存在的互不匹配现象而产生的技术。业务实体在内存中表现为对象,在数据库中表现为关系数据。ORM通过使用描…

【网络技术】HULK攻击实验

一、重要声明 请勿攻击公网!请勿攻击公网!请勿攻击公网! 一切责任自负!一切责任自负!一切责任自负! 二、工具介绍 HULK(Http Unbearable Load King,字面意思是“不能承受的HTTP&a…