【愚公系列】2023年10月 Java教学课程 078-网络编程UDP协议

在这里插入图片描述

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏


🚀一.UDP协议

UDP(User Datagram Protocol,用户数据报协议)是一种无连接协议,它提供了不可靠的数据传输服务。UDP协议没有数据重传和数据包状态确认机制,数据包发送出去后就无法保证是否能够被接收方正确接收。

尽管UDP在可靠性和可控性方面不如TCP,但其速度更快,开销更小,因此它在某些应用场景中更加适用,如视频、音频的实时传输、在线游戏等。

🔎1.UDP发送数据

方法名描述示例
DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造UDP数据包byte[] data = “Hello World”.getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(“localhost”), 8888);
DatagramSocket()构造UDP套接字DatagramSocket socket = new DatagramSocket();
send(DatagramPacket packet)发送UDP数据包byte[] data = “Hello World”.getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(“localhost”), 8888);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
receive(DatagramPacket packet)接收UDP数据包byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
DatagramSocket socket = new DatagramSocket(8888);
socket.receive(packet);
setSoTimeout(int timeout)设置套接字超时时间DatagramSocket socket = new DatagramSocket(8888);
socket.setSoTimeout(5000);

示例:

import java.net.*;

public class UDPSender {
    public static void main(String[] args) {
        try {
            // 创建数据报
            byte[] data = "Hello World".getBytes();
            DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("localhost"), 8888);
            // 创建套接字
            DatagramSocket socket = new DatagramSocket();
            // 发送数据报
            socket.send(packet);
            System.out.println("数据发送完毕");
            // 关闭套接字
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

import java.net.*;

public class UDPReceiver {
    public static void main(String[] args) {
        try {
            // 创建数据报
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            // 创建套接字
            DatagramSocket socket = new DatagramSocket(8888);
            // 接收数据报
            socket.receive(packet);
            System.out.println("接收到数据:" + new String(packet.getData(), 0, packet.getLength()));
            // 关闭套接字
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

🔎2.UDP接收数据

方法名返回类型描述示例
DatagramSocket(int port)DatagramSocket创建一个新的DatagramSocket对象,使用指定的本地端口DatagramSocket socket = new DatagramSocket(9999);
DatagramPacket(byte[] buf, int length)DatagramPacket创建一个DatagramPacket对象,用于接收数据byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
receive(DatagramPacket p)void接收数据报文socket.receive(packet);
getData()byte[]获取数据报文的字节数组byte[] data = packet.getData();
getLength()int获取数据报文的长度int length = packet.getLength();
getAddress()InetAddress获取数据报文的发送方地址InetAddress address = packet.getAddress();
getPort()int获取数据报文的发送方端口号int port = packet.getPort();

示例代码:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPServer {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(9999);
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        socket.receive(packet);
        String data = new String(packet.getData(), 0, packet.getLength());
        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        System.out.println("接收到数据:" + data + ",来自:" + address + ":" + port);
        socket.close();
    }
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPClient {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();
        String data = "Hello, UDP Server!";
        byte[] buf = data.getBytes();
        DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 9999);
        socket.send(packet);
        socket.close();
    }
}

🔎3.UDP通信案例

以下是一个使用UDP进行实际通信的聊天程序,用户可以向其他用户发送消息。

服务器端代码:

import java.net.*;

public class UDPServer {
    public static void main(String[] args) throws Exception {
        DatagramSocket serverSocket = new DatagramSocket(9876);
        System.out.println("Server is running on port 9876.\n");
        byte[] receiveData = new byte[1024];
        byte[] sendData = new byte[1024];
        while(true) {
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(receivePacket);
            String message = new String(receivePacket.getData()).trim();
            System.out.println("\nReceived message from client: " + message);

            InetAddress IPAddress = receivePacket.getAddress();
            int port = receivePacket.getPort();

            String[] messageArray = message.split(" ");
            String messageType = messageArray[0];
            String senderName = messageArray[1];
            String messageText = "";

            if(messageArray.length > 2) {
                for(int i=2; i<messageArray.length; i++) {
                    messageText += messageArray[i] + " ";
                }
            }

            String response = "";

            if(messageType.equals("JOIN")) {
                response = "Server: " + senderName + " has joined the chat.";
            } else if(messageType.equals("MESSAGE")) {
                response = senderName + ": " + messageText;
            } else if(messageType.equals("LEAVE")) {
                response = "Server: " + senderName + " has left the chat.";
            }

            sendData = response.getBytes();

            DatagramPacket sendPacket =
                new DatagramPacket(sendData, sendData.length, IPAddress, port);
            serverSocket.send(sendPacket);
        }
    }
}

客户端代码:

import java.net.*;

public class UDPClient {
	public static void main(String[] args) throws Exception {
		InetAddress IPAddress = InetAddress.getLocalHost();
		DatagramSocket clientSocket = new DatagramSocket();
		System.out.println("Welcome to the chat room!\n");
		while(true) {
			String message = getMessageFromUser();
			byte[] sendData = new byte[1024];
			byte[] receiveData = new byte[1024];
			sendData = message.getBytes();
			DatagramPacket sendPacket =
				new DatagramPacket(sendData, sendData.length, IPAddress, 9876);
			clientSocket.send(sendPacket);
			if(message.equals("LEAVE")) {
				break;
			}
			DatagramPacket receivePacket =
				new DatagramPacket(receiveData, receiveData.length);
			clientSocket.receive(receivePacket);
			String response = new String(receivePacket.getData()).trim();
			System.out.println("\n" + response);
		}
		clientSocket.close();
	}

	public static String getMessageFromUser() {
		String message = "";
		System.out.print("Enter message (JOIN, MESSAGE, or LEAVE): ");
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			message = br.readLine();
			if(message.equals("MESSAGE")) {
				System.out.print("Enter message text: ");
				message += " " + br.readLine();
			} else if(message.equals("JOIN")) {
				System.out.print("Enter your name: ");
				message += " " + br.readLine();
			} else if(message.equals("LEAVE")) {
				System.out.print("Are you sure you want to leave? (Y/N): ");
				String answer = br.readLine();
				if(answer.equals("Y")) {
					System.out.println("Goodbye!");
				} else {
					message = getMessageFromUser();
				}
			} else {
				System.out.println("Invalid message type. Please try again.\n");
				message = getMessageFromUser();
			}
		} catch(Exception e) {
			System.out.println("Error: " + e.getMessage());
			System.exit(0);
		}
		return message;
	}
}

在这个案例中,客户端输入JOIN加上自己的名字来加入聊天室,输入MESSAGE加上要发送的消息文本来发送消息,输入LEAVE来离开聊天室。客户端会将这些消息转换为字符串并发送到服务器。服务器将消息解析,并返回相应的响应消息。客户端会在控制台上显示这些响应消息。

实际上,UDP还可以用于实现各种游戏和实时应用程序,因为它可以实现快速而精细的数据传输。

🔎4.UDP三种通讯方式

UDP(User Datagram Protocol)是一种无连接的、无状态的通信协议,主要用于快速传输小数据包,不保证数据的可靠性和顺序。UDP有三种通讯方式,分别是单播、广播和组播。

  1. 单播(Unicast):一对一通讯方式,即一个发送端发送数据包到一个接收端。

  2. 广播(Broadcast):一对多通讯方式,即一个发送端发送数据包到所有在同一网络中的接收端。

  3. 组播(Multicast):多对多通讯方式,即一个发送端向一个多播组发送数据包,并且只有加入该组的接收端才能接收到数据包。组播需要设定特殊的IP地址范围,例如224.0.0.0 - 239.255.255.255是保留的组播地址范围。

🦋4.1 UDP组播实现

UDP组播是一种UDP数据包的传输方式,它通过一个组播地址将数据包发送给多个接收方,而不是单个目的地。Java中的UDP组播使用的是MulticastSocket类。

原理:

UDP组播是基于IP多播实现的。在IP多播中,一个数据报被发送到一个专门的IP地址,该地址被指定为多个接收方的标识符。在网络上,多个接收方共享同一个IP地址,同时使用不同的端口号进行通信。当数据包被发送到多播地址时,路由器会将数据包复制并传递到所有连接到该地址的接收方。

Java中的UDP组播示例:

以下是一个简单的Java UDP组播示例,其中客户端和服务器端通过组播地址进行通信。

服务端:

import java.net.*;

public class MulticastServer {
   public static void main(String[] args) throws Exception {
      MulticastSocket serverSocket = new MulticastSocket();
      String message = "Hello, World!";
      InetAddress group = InetAddress.getByName("224.0.0.1"); // 组播地址

      DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), group, 1234);
      serverSocket.send(packet);
      serverSocket.close();
   }
}

客户端:

import java.net.*;

public class MulticastClient {
   public static void main(String[] args) throws Exception {
      MulticastSocket clientSocket = new MulticastSocket(1234);
      InetAddress group = InetAddress.getByName("224.0.0.1"); // 组播地址
      clientSocket.joinGroup(group);

      byte[] buffer = new byte[1024];
      DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
      clientSocket.receive(packet);

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

      clientSocket.leaveGroup(group);
      clientSocket.close();
   }
}

服务端使用MulticastSocket类创建一个UDP套接字,并将数据包发送到组播地址224.0.0.1。客户端也使用MulticastSocket类创建一个UDP套接字,并加入到与服务端相同的组播地址。客户端接收到数据包后,打印消息并离开组播组。

🦋4.2 UDP广播实现

UDP广播是一种发送和接收UDP数据报的广播形式,UDP广播使用IP地址 255.255.255.255 或某个特定的广播地址。在局域网中,所有与该网络连通的主机都会接收到UDP广播数据包。

import java.net.*;

public class UDPBroadcastSender {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();
        socket.setBroadcast(true);
        
        byte[] buffer = "This is a UDP broadcast message".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 8888);
        socket.send(packet);

        System.out.println("UDP broadcast message sent");
        socket.close();
    }
}

我们首先创建了一个DatagramSocket对象,并将其设置为支持广播。然后,我们使用BufferedWriter将要发送的消息转换为字节数组,并创建一个DatagramPacket对象,该对象包含了要发送的数据、目标地址和端口号。最后,我们通过调用DatagramSocket的send()方法来发送UDP广播消息。

UDP广播消息的示例代码:

import java.net.*;

public class UDPBroadcastReceiver {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8888);
        socket.setBroadcast(true);

        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            socket.receive(packet);
            String message = new String(packet.getData(), 0, packet.getLength());
            System.out.println("UDP broadcast message received: " + message);
        }
    }
}

我们创建了一个DatagramSocket对象并绑定到8888端口,然后将其设置为支持广播。接着,我们创建一个字节数组和一个DatagramPacket对象,并在while循环中使用DatagramSocket的receive()方法来接收UDP广播消息。当消息到来时,我们将其转换为字符串并打印到控制台上。


🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

在这里插入图片描述

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚公搬代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值