JAVASE进阶:网络编程(编程实现TCP、UDP传输)

news/2024/5/18 12:59:50 标签: 网络, tcp/ip, udp, javase, java, 面试, 网络协议

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:JAVASE进阶:高级写法——方法引用(Mybatis-Plus必学前置知识)
📚订阅专栏:JAVASE进阶
希望文章对你们有所帮助

其实我认为javase>javase中的File流、I/O流(字节流、字符流)等都是很重要的,但是内容很多就没有具体去做总结了,不过这里总结的网络编程中也会用到I/O流中的不少思想,大家可以边学习网络编程边了解I/O流编程,对于I/O流大家需要自行去系统学习或回顾。

网络编程(编程实现TCP、UDP传输)

  • 网络编程介绍
  • 网络编程三要素
    • 三要素——IP
      • ipv4的一些细节
      • InetAddress类的使用
    • 三要素——端口号
    • 三要素——协议
  • UDP协议编程
    • 发送数据
    • 接收数据
  • TCP协议编程
    • 发送数据
    • 接收数据
  • 三次握手和四次挥手

网络编程介绍

网络编程就是在网络通信协议下,不同计算机上运行的程序,进行的数据传输。java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。

常见的软件架构有两种,即B/S架构(浏览器/服务器)和C/S架构(客户端/服务器)。
B/S架构无需开发客户端,只需要页面+服务端,用户不需要下载,打开浏览器就能使用,但若应用过大, 用户体验就会受到影响。
C/S架构的画面可以做的更精美,用户体验更好,但需要开发客户端,也需要开发服务端,且用户时不时的要更新。

网络编程三要素

IP:设备在网络中的地址,是唯一的标识
端口号:应用程序在设备中唯一的标识
协议:数据在网络中传输的规则,常见协议有UDP、TCP、http、https、ftp

三要素——IP

IP全称Internet Protocol,是互联网协议地址,也称IP地址,是分配给上网设备的数字标签,常见的IP分为ipv4和ipv6。

1、ipv4:采用32位地址长度,分为4组,采用点分十进制表示法,最多只有2^32,目前已经分配完毕

2、ipv6:采用128位地址长度,分为8组,采用冒分十六进制表示法,如果计算出的十六进制表示形式中间有多个连续的0,就可以接着采用0位压缩表示法(有一些计网的基础,看名字都挺容易理解的,如果有点模糊可以自行去查阅),最多有2^128个IP,可以为地球上的每一粒沙子分配IP。

ipv4的一些细节

实际上ipv6还没有普及,而ipv4明明已经分配完,但是我们还是主要使用了ipv4。

ipv4的地址可以分为公网地址(万维网用)和私有地址(局域网用),192.168.0.0-192.168.255.255是私有地址的范围。

localhost:127.0.0.1,是回送地址或本地回环地址,只会寻找当地所在本机。

考虑一个问题:若192.168.177.130是我电脑的IP,那么这个IP和127.0.0.1是否一致
答案:不一致,因为不同的局域网分配给我的IP是不一致的,所以平时写demo最好用127.0.0.1或localhost

常用cmd命令:

ipconfig:查看本地ip地址
ping:检查网络是否连通

InetAddress类的使用

InetAddress底层分别有针对ipv4网络和ipv6网络的,InetAddress本身没有构造方法,需要使用它的静态方法getByName去获取到对象,这个方法的底层就会判断我们的ip使用是ipv4还是ipv6的。
其基本使用代码如下:

java">//获取InetAddress对象,可以传递ip地址或主机名
InetAddress address = InetAddress.getByName("192.168.177.130");
//获取这个IP的主机名
String name = address.getHostName();
//获取IP值
String name = address.getHostAddress();

三要素——端口号

端口号是应用程序在设备中唯一的标识,是由2个字节表示的整数,取值范围:0-65535。
其中0-1023之间的端口号用于一些知名的网络服务或应用,我们自己使用1024以上的端口号就可以了,需要注意一个端口号只能被一个应用程序使用。

三要素——协议

计算机网络中,连接和通信的规则被称为网络通信协议。最初使用的OSI参考模型(物链网传会表应)太理想化,事实上的国际标准为TCP/IP参考模型(物理链路层、网络层、传输层、应用层),这些在学习计算机网络的时候都学习过。

每一层都会有一些相应的协议:

应用层:HTTP、FTP、TelNet、DNS
传输层:TCP、UDP
网络层:IP、ICMP、ARP
物理链路层:硬件设备二进制数

在这里我们将会学习TCP、UDP协议,并且进行演示。

UDP协议:

1、用户数据报协议
2、UDP是面向无连接的通信协议。
3、速度快,有大小限制,一次最多发送64K,数据不安全,易丢失数据

TCP协议:

1、传输控制协议
2、TCP是面向连接的通信协议
3、速度慢,但没有大小限制,数据安全

UDP协议编程

UDP协议的发送数据、接收数据都需要用到DatagramSocket类。

发送数据

发送的数据是字节数组形式,因此需要将字符串转化为字节数组,然后接收方把字节数组再转化回来。

java">public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        /**
         * 创建DatagramSocket对象,可以直接指定端口,那么以后就通过这个端口往外发送数据
         * 若是空参构造,将会在所有可用的端口中随机指定一个进行使用
         */
        DatagramSocket ds = new DatagramSocket();

        /**
         * 打包数据,ds的send方法需要DatagramPacket对象表示包装数据
         * DatagramPacket需要的参数:
         *      1、要发送的数据(byte数组形式)
         *      2、开始索引(非必要)
         *      3、长度
         *      4、要发送的地址
         *      5、端口号
         */
        //要发送的数据
        String str = "孩儿立志出乡关,学不成名誓不还";
        byte[] bytes = str.getBytes();
        //要发送的地址
        InetAddress address = InetAddress.getByName("127.0.0.1");
        //指定发送到哪个端口,发送方端口可以不确定,但是发送到哪个端口要指定
        int port = 10086;
        //打包数据
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);

        /**
         * 发送数据
         */
        ds.send(packet);

        /**
         * 释放资源
         */
        ds.close();
    }
}

接收数据

java">public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        /**
         * 创建DatagramSocket对象,端口号必须指定成是之前发送的10086端口
         */
        DatagramSocket ds = new DatagramSocket(10086);

        /**
         * 新建一个箱子用于接收数据,无需再指定地址和端口号,因为ds已经指定了
         */
        //空箱子
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);

        /**
         * 使用receive方法取出数据,该方法是阻塞的,如果没有消息发出,这个方法就一直等待
         */
        ds.receive(packet);


        /**
         * 解析数据
         */
        //发过来的数据是什么
        byte[] data = packet.getData();
        //发送过来的数据的长度如何
        int length = packet.getLength();
        //是从哪个地址以及端口号传输过来的数据
        InetAddress address = packet.getAddress();
        int port = packet.getPort();

        System.out.println(new String(data, 0, length));
        System.out.println("该数据是从" + address + "中的" + port + "这个端口发出的");

        /**
         * 释放资源
         */
        ds.close();
    }
}

TCP协议编程

TCP传输中,发送数据(客户端)需要定义Socket对象,而接受数据(服务器端)需要定义ServerSocket对象。

由于TCP传输需要使用I/O流相关函数,所以还需要注意好中文的乱码问题,当读取数据的时候不能再使用字节流来读取了,因为一个中文对应着两个字节,按字节流读取会发生乱码,应当使用字符流读取。

发送数据

根据I/O流的相关知识,要写数据,需要用到输出流OutputStream:

java">public class Client {
    public static void main(String[] args) throws IOException {
        /**
         * 创建Socket对象,创建对象的同时会连接服务器,若连接不上则会报错
         */
        Socket socket = new Socket("127.0.0.1", 9999);

        /**
         * 从连接通道中获取输出流,并可以写出数据
         */
        OutputStream outputStream = socket.getOutputStream();
        //写出数据
        outputStream.write("哈哈".getBytes());

        /**
         * 释放资源
         */
        outputStream.close();
        socket.close();
    }
}

接收数据

java">public class Server {
    public static void main(String[] args) throws IOException {
        /**
         * 创建ServerSocket对象
         */
        ServerSocket serverSocket = new ServerSocket(9999);

        /**
         * 监听客户端的连接,底层是阻塞式
         */
        Socket socket = serverSocket.accept();

        /**
         * 从连接通道中获取输入流来读取数据,拆分代码如下:
         *          InputStream inputStream = socket.getInputStream();
         *         //转换成字符流,因为一个汉字对应2个字节,用字节读取会乱码
         *         InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
         *         //利用缓存流提高效率
         *         BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
         */
        //写在一行:
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        int b;
        while((b = bufferedReader.read()) != -1){
            System.out.print((char) b);
        }

        /**
         * 释放资源,注意需要先释放socket,才能释放serverSocket(需要保证数据处理完毕)
         */
        socket.close();
        serverSocket.close();

    }
}

三次握手和四次挥手

三次握手需要保证连接的建立,流程如下:

1、客户端向服务器端发送连接请求,等待服务器确认
2、服务器端向客户端返回一个确认信息,告诉客户端收到了请求
3、客户端向服务器再次发送确认信息(确认了他的确认),连接建立

四次挥手的作用是确认连接断开,且数据处理完毕,流程如下:

1、客户端向服务器发出取消连接请求
2、服务器向客户端返回一个响应,表示收到客户端取消请求(不是确认请求!)
3、服务器将最后的数据处理完毕
4、服务器向客户端发出确认取消信息
5、客户端再次发送确认消息,连接取消

重点是挥手的2次确认信息发出之前,必须要让服务端把消息都处理完毕。


http://www.niftyadmin.cn/n/5372811.html

相关文章

【 buuctf--刷新过的图片】

前言:这题主要运用到了新的工具F5-steganography由于 java 环境不合适的原因,我不得不重新配java11.0.18。 具体思路:非常帅气的一张图片。。。用 binwalk,stegsolve,zsteg,exiftool 等工具无果后&#xf…

uv机器电机方向极性

爱普生主板设置X、Y 电机方向极性:请根据实际情况设置,开机初始化时如果电机运动方向反了则修改此极性。 理光主板设置X、Y 电机方向极性

django中实现适配器模式

在Django中实现适配器模式(Adapter Pattern)涉及到创建一个适配器类,它允许不兼容的接口之间进行交互。适配器模式通常用于将一个类的接口转换为另一个客户端期望的接口。 一:实现例子 下面是一个简单的例子,演示如何…

STM32 与 ARM 的联系

STM32 和 ARM 是两个不同的概念,但它们之间存在一定的联系。 STM32是一种微控制器产品,由意法半导体(STMicroelectronics)推出,其内核采用了 ARM Cortex-M 核。ARM 是一家英国芯片设计公司,专注于设计和许可…

代码随想录算法训练营第44天 | 完全背包理论基础 518.零钱兑换II 377.组合总和 Ⅳ

完全背包理论基础 完全背包与01背包只相差在物品是无限取用的。因此和01背包相比第二层对背包容量的遍历应该是正序的&#xff0c;而且正因为这个正序&#xff0c;使得在纯完全背包问题中&#xff0c;背包容量和物品的遍历是可以倒过来的。 #include <bits/stdc.h> usi…

python基础教程九 抽象四(函数参数终)

文章预览&#xff1a; 1. 分配参数2. 作用域3. 递归1. 俩个经典案例&#xff1a;阶层和幂2. 递归的意义1. 递归二分查找1. 二分查找的条件1. 二分查找的意义 1. 分配参数 前面介绍了如何将参数收集到元组和字典当中&#xff0c;但同样的俩个运算符&#xff0c;也可以执行相反的…

List stream的9种常用功能

1、List 转List List llla Arrays.asList(“1”,“2”).stream().map(Long::parseLong).collect(Collectors.toList()); 2、List转类型List、List、List //&#xff08;1&#xff09;、List中的String属性转List List userNameList list.stream().map(UserInfo::getUserName…

CVE-2018-19518 漏洞复现

CVE-2018-19518 漏洞介绍 IMAP协议&#xff08;因特网消息访问协议&#xff09;它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息&#xff0c;下载邮件等。它运行在TCP/IP协议之上&#xff0c;使用的端口是143。在php中调用的是imap_open函数。 PHP 的…