26-网络通信

news2024/11/24 18:31:08

网络通信

什么是网络编程?
可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)。
java.net.包下提供了网络编程的解决方案!
基本的通信架构有2种形式:CS架构( Client客户端/Server服务端 ) 、 BS架构(Browser浏览器/Server服务端)。

image-20230811093617412

image-20230811093708272

我们java的重点是开发BS架构
无论是CS架构,还是BS架构的软件都必须依赖网络编程

网络通信的三要素

  1. IP地址 设备在网络中的地址,是唯一的标识。
  2. 端口 应用程序在设备中唯一的标识
  3. 协议 连接和数据在网络中传输的规则。

IP地址

IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标志。
IP地址有两种形式:IPv4、IPv6

IPV4

image-20230811094428007

IPV6

32为的IP地址根本不够为我们如此多的IP的地址进行编号,所以演变出了IPV6地址
IPv6:共128位,号称可以为地球每一粒沙子编号。
IPv6分成8段表示,每段每四位编码成一个十六进制位表示, 数之间用冒号(:)分开。
image-20230811095044814

IP域名

域名就是最后也要转化为IP的
image-20230811095232838

特殊IP

公网IP,内网IP
公网IP:是可以连接互联网的IP地址;内网IP:也叫局域网IP,只能组织机构内部使用。
192.168. 开头的就是常见的局域网地址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用。
特殊IP地址:非常重要
127.0.0.1、localhost:代表本机IP,只会寻找当前所在的主机。
IP常用命令:
ipconfig:查看本机IP地址。
ping IP地址:检查网络是否连通。

InerAddress命令
名称说明
public static InetAddress getLocalHost()获取本机IP,会以一个inetAddress的对象返回
public static InetAddress getByName(String host)根据ip地址或者域名,返回一个inetAdress对象
public String getHostName()获取该ip地址对象对应的主机名。
public String getHostAddress()获取该ip地址对象中的ip地址信息。
public boolean isReachable(int timeout)在指定毫秒内,判断主机与该ip对应的主机是否能连通
举例
    public static void main(String[] args) {
        try {
            InetAddress ia = InetAddress.getLocalHost();  //获取本机IP
            InetAddress bd = InetAddress.getByName("www.baidu.com");  //获取这个网址的ip
            System.out.println(ia);  //输出这个本机ip的主机
            System.out.println(ia.getHostName());  //输出这个本机ip的名字
            System.out.println(ia.getHostAddress()); //输出这个本机ip的地址
            System.out.println(bd.isReachable(1000)); //判断baidu的主机和本机是否能够在1000ms内进行连接成功
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出结果
DESKTOP-ROKA7MJ/111.111.111.1 (这个本机ip我已经修改了,防止自己的ip泄露,这里随便编了一个,为了能够更好的展示结果)
DESKTOP-ROKA7MJ
111.111.111.1
www.baidu.com/180.101.50.188
true

端口号

端口
标记正在计算机设备上运行的应用程序的,被规定为一个 16 位的二进制,范围是 0~65535。
分类
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)
注册端口:1024~49151,分配给用户进程或某些应用程序。
动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错。

协议

网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式网络互联标准:OSI网络参考模型
OSI网络参考模型:全球网络互联标准。
TCP/IP 网络模型:事实上的国际标准。(大四的课程, 进行网络通信)

OSI网络参考模型TCP/IP网络模型各层对应面向操作
应用层应用层HTTP、FTP、SMTP…应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
表示层应用层HTTP、FTP、SMTP…应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
会话层应用层HTTP、FTP、SMTP…应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
传输层传输层UDP、TCP…选择使用的TCP , UDP协议
网络层网络层IP…封装源和目标IP
数据链路层数据链路层+ 物理比特流…物理设备中传输
物理层数据链路层+ 物理比特流…比特流…

UDP(User Datagram Protocol):用户数据报协议; TCP(Transmission Control Protocol) :传输控制协议。

UDP协议

特点:无连接、不可靠通信。
不事先建立连接,数据按照包发,一包数据包含:自己的IP、程序端口,目的地IP、程序端口和数据(限制在64KB内)等。
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的 。
语音童话,还有视频直播我们可以用这个UDP通信,因为数据的丢失对这个影响不大

TCP协议

特点:面向连接、可靠通信。
TCP的最终目的:要保证在不可靠的信道上实现可靠的传输。
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。

image-20230811105551312

image-20230811105831833

image-20230811105854535

UDP通信的快速入门

常用方法

UDP通信
特点:无连接、不可靠通信。
不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。
Java提供了一个java.net.DatagramSocket类来实现UDP通信。
DatagramSocket: 用于创建客户端、服务端

构造器说明
public DatagramSocket()创建客户端的Socket对象, 系统会随机分配一个端口号。
public DatagramSocket(int port)创建服务端的Socket对象, 并指定端口号
方法说明
public void send(DatagramPacketdp)发送数据包
public void receive(DatagramPacket p)使用数据包接收数据

DatagramPacket:创建数据包

构造器说明
public DatagramPacket(byte[] buf, int length, InetAddress address, int port)创建发出去的数据包对象
public DatagramPacket(byte[] buf, int length)创建用来接收数据的数据包
方法说明
public int getLength()获取数据包,实际接收到的字节个数

一发一收

创建一个客户端对象

    public static void main(String[] args) throws Exception {
        //1. 创建客户端对象,发数据的人
        DatagramSocket ds = new DatagramSocket();

        //2 创建数据包对象封装要发出去的数据(创建一个韭菜盒子)  
        //参数一:封装要发出去的数据
        //参数二,发出去的数据大小,字节个数
        //参数三:服务端的IP地址
        // 参数四: 服务端程序的端口
        byte[] bytes = "我爱你,你爱我,蜜雪冰城甜蜜蜜".getBytes();
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);
        ds.send(dp);
        System.out.println("客户端数据发送完毕");
        ds.close(); //释放资源
    }

创建一个服务端对象,注册端口

    public static void main(String[] args) throws Exception {
        //创建一个服务端对象,注册端口
        System.out.println("------------");
        DatagramSocket ds = new DatagramSocket(6666);
        //创建一个数据包对象,用于接受数据
        byte [] bytes = new byte[1024*64]; //一个数据包最大不能超过64kb,所以我们接收的时候最好用最大的,防止接收不完
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        ds.receive(dp);
        //读取多少就倒出多少
        String s = new String(bytes,0,dp.getLength());
        System.out.println(s);

    }

多发多收

客户端.可以多次运行

        Scanner input  = new Scanner(System.in);
        while (true) {
            System.out.println("请说");
            String msg = input.nextLine();
            //退出这个循环
            if(msg.equals("end")){
                System.out.println("退出成功,欢迎下次使用");
                ds.close(); //释放资源
                break;
            }
            byte[] bytes = msg.getBytes();
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);
            ds.send(dp);
            System.out.println("客户端数据发送完毕");
        }

服务端没有必要关闭

        DatagramSocket ds = new DatagramSocket(6666);
        byte [] bytes = new byte[1024*64]; //一个数据包最大不能超过64kb,所以我们接收的时候最好用最大的,防止接收不完
        while (true) {
            System.out.println("------------");
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
            ds.receive(dp);
            //读取多少就倒出多少
            String s = new String(bytes,0,dp.getLength());
            System.out.println(s);
        }

TCP通信

一定要注意前后服务端和客户端要一一对应,否则就容易出错

特点:面向连接、可靠通信。
通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端。
Java提供了一个java.net.Socket类来实现TCP通信。

image-20230811120040094

TCP通信之-客户端开发

客户端程序就是通过java.net包下的Socket类来实现的。

常用方法

构造器说明
public Socket(String host , int port)根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
方法说明
public OutputStream getOutputStream()获得字节输出流对象
public InputStream getInputStream()获得字节输入流对象

TCP通信之-服务端开发

服务端是通过java.net包下的ServerSocket类来实现的。

构造器说明
public ServerSocket(int port)为服务端程序注册端口
方法说明
public Socket accept()阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象。

举例

单发单收
服务端, 从外读input

 //服务端的开发
        ServerSocket serverSocket = new ServerSocket(8888);
        //使用servesocket对象,调用accept[t方法,等待客户端的连接请求
        Socket accept = serverSocket.accept();
        //从socket通信管道中获取一个字节输入流
        InputStream is = accept.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        //读取数据
        System.out.println(dis.readUTF());
        dis.close();
        serverSocket.close();

客户端,往外写 output

//创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);

        //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        dos.writeUTF("我喜欢你");
        dos.close();
        socket.close();

多发多收
服务端, 从外读 input

//服务端的开发
        ServerSocket serverSocket = new ServerSocket(8888);
        Socket accept = serverSocket.accept();
        //使用servesocket对象,调用accept[t方法,等待客户端的连接请求
        //从socket通信管道中的大奥一个字节输入流
        InputStream is = accept.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        while (true) {
            System.out.println("------------");
            //读取数据
            System.out.println(dis.readUTF());
        }

客户端, 往外写output

        //创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        Scanner input = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        while (true) {
            //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
            String msg = input.nextLine();
            if(msg.equals("end")){
                System.out.println("退出客户端");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(msg);
            dos.flush();
            System.out.println("写入成功");
        }

如果我们这个客户端挂了,那么服务端也会挂

TCP通信,支持与多个客户端同时通信

目前我们开发的服务端程序,是否可以支持与多个客户端同时通信 ?
不可以的。
因为服务端现在只有一个主线程,只能处理一个客户端的消息。
UDP不需要进行连接,只需要进行发送数据包就好了
image-20230811124405412
所以我们要又多线程来实现多个客户端进行通信
服务端,创建多线程

        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器启动");
        while (true) {
            Socket accept = serverSocket.accept();
            System.out.println("有人上线了,地址是"+accept.getRemoteSocketAddress() );
            new TCPThread(accept).start();
        }

线程对象

public class TCPThread extends Thread{
    private Socket socket;
    public TCPThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run(){
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                //读取数据,防止服务端关闭这里崩溃
                try {
                    System.out.println(dis.readUTF());
                    System.out.println(socket.getRemoteSocketAddress()+"输入了数据:");
                } catch (Exception e) {
                    System.out.println(socket.getRemoteSocketAddress()+"关闭");
                    socket.close();
                    dis.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端

        //创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        Scanner input = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        while (true) {
            //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
            String msg = input.nextLine();
            if(msg.equals("end")){
                System.out.println("退出客户端");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(msg);
            dos.flush();
            System.out.println("写入成功");
        }

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

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

相关文章

Python无废话-办公自动化Excel修改数据

如何修改Excel 符合条件的数据?用Python 几行代码搞定。 需求:将销售明细表的产品名称为PG手机、HW手机、HW电脑的零售价格分别修改为4500、5500、7500,并保存Excel文件。如下图 Python 修改Excel 数据,常见步骤: 1&…

又添十万字-CS的陋室2023年文章合集来袭

趁着国庆中秋双节,整理了“22年文章合集”以来的所有新文章,在此给大家带来我的文章合集2023版。 文章合集收录: 文章合集2022以来的所有文章,包括“前沿重器”和“心法利器”。 前沿重器28-34共7篇,约2.6万字。心法利…

《C和指针》笔记30:函数声明数组参数、数组初始化方式和字符数组的初始化

文章目录 1. 函数声明数组参数2. 数组初始化方式2.1 静态初始化2.2 自动变量初始化 2.2 字符数组的初始化 1. 函数声明数组参数 下面两个函数原型是一样的: int strlen( char *string ); int strlen( char string[] );可以使用任何一种声明,但哪个“更…

一文拿捏SpringMVC的调用流程

SpringMVC的调用流程 1.核心元素: DispatcherServlet(前端控制器)HandlerMapping(处理器映射器)HandlerAdapter(处理器适配器) ---> Handler(处理器)ViewResolver(视图解析器 )---> view(视图) 2.调用流程 用户发送请求到前端控制器前端控制器接收用户请求…

7.JavaScript-vue

1 JavaScript html完成了架子,css做了美化,但是网页是死的,我们需要给他注入灵魂,所以接下来我们需要学习JavaScript,这门语言会让我们的页面能够和用户进行交互。 1.1 介绍 通过代码/js效果演示提供资料进行效果演…

<C++> STL_bitset使用和模拟实现

bitset的介绍 位图的引入 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中? 要判断一个数是否在某一堆数中,我们可能会想到如下方法: 将这一堆数进行排序&#xff0…

机器学习必修课 - 如何处理缺失数据

运行环境:Google Colab 处理缺失数据可简单分为两种方法:1. 删除具有缺失值的列 2. 填充 !git clone https://github.com/JeffereyWu/Housing-prices-data.git下载数据集 import pandas as pd from sklearn.model_selection import train_test_split导…

EM@常用三角函数图象性质(中学部分)

文章目录 abstract正弦函数正弦型函数转动相关概念旋转角速度转动周期转动频率初相小结 余弦函数的图象与性质性质 正切函数的图象和性质由已知三角函数值求角任意角范围内反三角函数(限定范围内)反正弦反余弦反正切 abstract 讨论 sin ⁡ , cos ⁡ , tan ⁡ \sin,\cos,\tan s…

WEB 3D 技术,通过node环境创建一个three案例

好 文章 前端3D Three.js 在本地搭建一个官方网站 中我们 搭建了一个Three的官网 现在呢 我们就来创建第一个ThreeJs的资源 这里呢 我们还是选择一个脚手架的开发模式 因为现在基本所有的前端都在使用这样的开发方式 这里 我们创建一个文件夹目录 作为我们项目的存放目录 我们…

【MySQL教程】| (1-1) 2023MySQL-8.1.0 安装教程

文章目录 一、安装包下载二、安装配置1、解压安装包2、编写MySQL配置文件3、初始化MySQL数据库3、安装mysql服务并启动4、MySQL服务5、连接MySQL6、修改密码 三、配置环境变量四、防止mysql自启动拖慢开机时间 近日有粉丝问到mysql在win11的安装中遇到一些问题,应粉…

基于 QT 实现 Task Timer,高效利用时间

一、开发环境 Ubuntu 20.04 QT6.0 二、新建 Qt Wigets Application 这里的基类选择 Wigets, pro 配置文件添加 sql 模块,需要用到 sqlite, QT sql 三、添加数据库连接头文件 // connection.h #ifndef CONNECTION_H #define CONNECTION_…

pycharm配置python3.8版本专门用于undecteded_chromedriver测试

pycharm配置python3.8版本专门用于undecteded_chromedriver测试 作者:虚坏叔叔 博客:https://pay.xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 一、Pycharm及python环境的配置 1.安装python-3.8.7rc1-amd64.e…

QT常用控件介绍

QT信号与槽机制 connect (A,SIGNLA(aaa()),B, SLOT(bbb())); GUI继承简介 布局管理器 垂直布局水平布局网格布局表单布局 输出控件 Label: 标签Text Browser: 文本浏览器Graphics View : 图形视图框架Calendar Widget: 日历控件LCD Number: 液晶字体数…

游戏逆向中的 NoClip 手段和安全应对方式

文章目录 墙壁边界寻找碰撞 NoClip 是一种典型的黑客行为,允许你穿过墙壁,所以 NoClip 又可以认为是避免碰撞体积的行为 墙壁边界 游戏中设置了碰撞体作为墙壁边界,是 玩家对象 和墙壁发生了碰撞,而不是 相机 玩家对象有他的 X…

操作系统初探 - 进程的概念

目录 预备知识 冯诺依曼和现代计算机结构 操作系统的理解 进程和PCB的概念 PCB中的信息 查看进程信息的指令 - ps pid 进程状态 预备知识 在学习操作系统之前我们需要先了解一下如下的预备知识。 冯诺依曼和现代计算机结构 美籍匈牙利科学家冯诺依曼最先提出“程序存…

【CAD二次开发】给CAD添加TRUSTEDPATHS避免dll插件信任弹窗

找到配置文件目录,遍历下面的每个配置文件; 找到 Variables 下的TRUSTEDPATHS项目;在后面添加新的目录即可,多个目录使用分号分隔; public static void AddPath(string trusedPath){// 指定注册表键的路径

画CMB天图使用Planck配色方案

使用Planck的配色方案: 全天图: 或者方形图: 使用下面设置即可: import pspy, pixell from pspy.so_config import DEFAULT_DATA_DIR pixell.colorize.mpl_setdefault("planck")此方法不会改变matplotlib默认配色方案…

浏览器指定DNS

edge--设置 https://dns.alidns.com/dns-query

JavaSE | 初识Java(六) | 数组 (上)

数组的创建及初始化 T[] 数组名 new T[N]; //T:表示数组中存放元素的类型 //T[]:表示数组的类型 //N:表示数组的长度 int[] array1 new int[10]; // 创建一个可以容纳10个int类型元素的数组 double[] array2 new double[5]; // 创建一个可…

再次总结nios II 下载程序到板子上时出现 Downloading RLF Process failed的问题

之前也写过两篇关于NIOS II 出现:Downloading RLF Process failed的问题,但是总结都不是很全面,小梅哥的教程总结的比较全面特此记录。 问题:nios II 下载程序到板子上时出现 Downloading RLF Process failed的问题。 即当nios中…