【Java】UDP网络编程:无连接通信到Socket实战

活动发起人@小虚竹 想对你说:

这是一个以写作博客为目的的创作活动,旨在鼓励大学生博主们挖掘自己的创作潜能,展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴,那么,快来参加吧!我们一起发掘写作的魅力,书写出属于我们的故事。我们诚挚邀请你参加为期14天的创作挑战赛!

提醒:在发布作品前,请将不需要的内容删除。

各位看官,大家早安午安晚安呀~~~

如果您觉得这篇文章对您有帮助的话

欢迎您一键三连,小编尽全力做到更好
欢迎您分享给更多人哦

今天我们来学习【Java】UDP网络编程:无连接通信到Socket实战

目录

1.什么是网络编程?

2.TCP和UDP的区别

2.1.TCP是有连接的,UDP是无连接的(这里的连接是抽象的概念)

2.2.TCP是可靠传输,UDP是不可靠传输

2.3.TCP是面向字节流的,UDP是面向数据报的

2.4.TCP和UDP都是全双工的

[3.UDP的Socket API如何进行使用?](#3.UDP的Socket API如何进行使用?)

[4.这里我们将写一个简单的UDP客户端,服务器通信的程序,就简单的调用socket API(回显服务器)](#4.这里我们将写一个简单的UDP客户端,服务器通信的程序,就简单的调用socket API(回显服务器))

4.1.服务器代码解释


1.什么是网络编程?

网络编程:指网络上的主机,通过不同的进程 ,以编程的方式实现网络通信(或称为网络数据传输)

要想进行网络编程,首先要学会操作系统给我们提供的一组API,我们通过这些API才能进行网络编程。

这个API可以认为是应用层和传输层之间交互的路径。(我们只需要知道用户输入的是什么,然后调系统的API就可以完成网络通信)

传输层提供的两个主要网络协议是TCP和UDP :这两个协议的原理差距很大,因此通过这两个协议进行网络编程的时候就存在一些差别。故系统提供了两组API供我们使用

首先我们先了解一下两个协议大的方向的区别在哪里,具体细节我留到下一个博客进行讲解

2.TCP和UDP的区别

2.1.TCP是有连接的,UDP是无连接的(这里的连接是抽象的概念)

这里连接的本质上是建立连接的双方各自保留对方的信息,两个计算机建立连接,就是彼此保留了对方的关键信息

TCP想要通信,就需要先建立连接(保存对方信息)做完之后才能进行通信

(如果A想要和B建立连接,B拒绝了,那么通信就没办法完成)

UDP想要通信,就直接发送数据就可以了~~,不管你是否同意,UDP也不会保留对方的信息

(UDP什么也不知道,但是我们程序员要知道,UDP自己不保存,但是我们发送数据肯定还是要把对方的IP和端口号都发送过去)

2.2.TCP是可靠传输,UDP是不可靠传输

在网络通信中,A会给B发送一个消息,B不可能100%收到

但是可靠传输就是就算A的信息没有传输过去,A能知道,进一步在发送失败的时候采取一定的措施(就像微信发送消息没发送过去有一个红感叹号)

TCP内置了可靠传输,UDP没有(后面我会详细讲解)(但是你可靠传输考虑的东西就太多了,效率就要牺牲,但是我们还是通过一些方法能补救回来一点)

2.3.TCP是面向字节流的,UDP是面向数据报的

TCP和文件操作一样都是以字节为单位进行传输的

UDP是按照数据报(DatagramPacket)为单位进行传输(只能是数据报的整数倍)

2.4.TCP和UDP都是全双工的

3.UDP的Socket API如何进行使用?

首先关于InetAddress这个类

复制代码
try {
    InetAddress address = InetAddress.getByName("www.google.com");
    System.out.println("IP Address: " + address.getHostAddress());
} catch (UnknownHostException e) {
    e.printStackTrace();
}

结果:IP Address: 142.250.190.36

  • InetAddress:用于表示 IP 地址的类,支持 IPv4 和 IPv6。

  • getByName():用于解析主机名或 IP 字符串,返回InetAddress 对象。

  • IP 地址作为参数:在网络编程中,IP 地址是定位目标设备的关键,因此需要作为参数传入相关方法(这里就需要把IP地址传入getByNAme()方法里面进行解析域名)。

通过InetAddress和getByName(),Java 网络编程可以轻松处理 IP 地址和域名解析,简化了开发者的工作。

UDP协议中两个API使用方法:

复制代码
Socket 在 Java 中的本质:是一个基于流的通信端点抽象,接收数据报的时候就会抛出IO异常,
DatagramSocket 是 Java 中用于 UDP 通信的类。可以把它理解为一个 "邮筒":
邮筒的作用:你往邮筒里投递信件(数据包),邮递员(网络)会把信件送到目的地。

DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报的类

|----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| DatagramPacket(byte[] buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数 length) |
| DatagramPacket(byte[] buf, int offset, int length, SocketAddress address | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数 length)。address指定目的主机的IP和端口号 |

4.这里我们将写一个简单的UDP客户端,服务器通信的程序,就简单的调用socket API(回显服务器)

服务器在程序员手里,**一个服务器上面都有哪些程序和端口是可控的。**我们写代码的时候分配一个空闲的端口给服务器就行了

但是客户可能都不知道端口是啥意思,万一把这个端口和其他程序的端口搞一起了就不妙了,我们还是直接让系统给客户分配一个的好

4.1.服务器代码解释

复制代码
import com.sun.deploy.net.socket.UnixDomainSocket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    private DatagramSocket socket = null;
    private int port ;
    // 服务器指定端口号
    public UdpEchoServer(int port) throws SocketException {   // new一个Socket对象的时候会抛出这个异常
        socket = new DatagramSocket(port);
    }
    // 服务器启动!!!(原神启动!!!)
    public void start() throws IOException {   //Socket 在 Java 中的本质:是一个基于流的通信端点抽象,接收数据报的时候就会抛出IO异常
        while(true){  // 服务器要一直运行
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //我们申请4096个字节的数据
            socket.receive(requestPacket);//这是一个输出型参数
            //当前完成这个receive之后,数据是以二进制的方式存储在DatagramPacket中的
            // 如果我们想要把这里的数据显示出来,并且进行处理就需要把二进制数据转换成字符串
            // 收到这个数据报就需要进行解析,转换成字符串,我们能够看懂的

            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            String response =  process(request); // 回显服务器,什么都不用干(相当于我们已经解析完成了)
            //把响应写回客户端,肯定还是把数据报给写回去呀

            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());//   把字符串抓换成字节数组,以及字节数组的长度搞过去(老一套构建数据报的格式了
            //但是还是要获取到来的数据报的地址呀,不然不知道你发给哪个客户

            socket.send(responsePacket);
            // 我们再打印一个日志,记录这次数据交互的详细情况!
            System.out.printf("[%s : %d],req = %s,rep =  %s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
            // 把IP地址,端口号打印出来,以及请求和响应
        }
        // 我们还要理解getSocketAddress和getAddress的区别,前者返回IP地址和端口号,后者只返回IP地址

    }

    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }

}

有两个问题:

问题一:

不行,这里面如果有中文字符的话字符串长度就不是字节长度了

(UTF-8编码中文字符是3个字节,GBK编码里中文字符是2个字节)

问题二:

上述我写的代码里面为什么没有close?不写close不会文件资源泄露吗?

复制代码
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    /*
    1. 创建一个Socket对象,发送接收数据报
    2.我们初始化数据报的时候因为Udp是无连接的,因此我们需要把服务器的  IP和端口号都发送过去(两个成员变量)
    3. 肯定要把我们的字符串(发送的本质内容转换成字节数组,然后一起构造成数据报DatagramPacket
    4.把数据报发送出去
    5.接收数据报(给数据包申请字节空间)
    6.把数据报再转成字符串
    * */

    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort = 0;
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    //客户端启动!!!
    public void start() throws IOException {
        System.out.println("客户端启动!!!");
        Scanner scanner = new Scanner(System.in);
        while(true){
            String request = scanner.next();
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIP),serverPort);  //  把IP端口号都发送过去
            /*InetAddress:用于表示 IP 地址的类,支持 IPv4 和 IPv6。

            getByName():用于解析主机名或 IP 字符串或者域名,返回 InetAddress 对象*/

            //通过 InetAddress 和 getByName(),Java 网络编程可以轻松处理 IP 地址和域名解析,简化了开发者的工作。
            socket.send(requestPacket);
            //接收响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            // 把数据报里面的二进制数据转成我们能看懂的字符串
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }


    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start();
    }
}

刚才这个程序在一个主机上面(并没有实现真正的跨主机通信的效果)

服务器在我自己电脑上面,小明是访问不到的(除非小明和我在一个局域网里面)

但是如果我把这个程序部署到云服务上面我们就可以实现互相通信的效果了(自己的电脑没有公网IP)

总结:

上述就是【Java】UDP网络编程:无连接通信到Socket实战的全部内容啦~~~

能看到这里相信您一定对小编的文章有了一定的认可。

有什么问题欢迎各位大佬指出
欢迎各位大佬评论区留言修正~~
您的支持就是我最大的动力​​​!!!

相关推荐
java1234_小锋3 分钟前
Spring Bean有哪几种配置方式?
java·后端·spring
?abc!4 分钟前
缓存(5):常见 缓存数据淘汰算法/缓存清空策略
java·算法·缓存
firshman_start16 分钟前
第十五章,SSL VPN
网络
DanB2417 分钟前
Java笔记4
java·开发语言·笔记
Johnstons22 分钟前
AnaTraf:深度解析网络性能分析(NPM)
前端·网络·安全·web安全·npm·网络流量监控·网络流量分析
Dddle125 分钟前
C++:this指针
java·c语言·开发语言·c++
落——枫27 分钟前
路由交换实验
网络
Johny_Zhao30 分钟前
K8S+nginx+MYSQL+TOMCAT高可用架构企业自建网站
linux·网络·mysql·nginx·网络安全·信息安全·tomcat·云计算·shell·yum源·系统运维·itsm
小诸葛的博客42 分钟前
华为ensp实现跨vlan通信
网络·华为·智能路由器
稳联技术1 小时前
Ethercat转Profinet网关如何用“协议翻译术“打通自动化产线任督二脉
linux·服务器·网络