java 网络编程基础 UDP协议的Socket:DatagramSocket;广播Socket:MulticastSocket
什么是UDP协议:
UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket 但这两个 Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象。Java 提供了DatagramSocket对象作为基于UDP协议的Socket。使用DatagramPacket代表 DatagramSocket发送、接收的数据包。
UDP协议从问世至今已经被使用了很多年,虽然UDP协议目前应用不如TCP协议广泛,但 UDP协议依然是一个非常实用和可行的网络传输层协议。尤其是在一些实时性很强的应用场景中,比如网络游戏、视频会议等,UDP协议的快速更具有独特的魅力。
UDP协议是一种面向非连接的协议,面向非连接指的是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。至于对方是否可以接收到这些数据内容,UDP协议无法控制,因此说UDP议是一种不可靠的协议UDP协议适用于一次只传送少量数据、对可靠性要求不高的应用环境。因为UDP协议是面向非连接的协议,没有建立连接的过程,因此它的通信效率很高。但也正因为如此,它的可靠性不如TCP协议。
UDP 协议和 TCP 协议简单对比如下
(1),TCP协议: 可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。
(2),UDP协议: 不可靠,差错控制开销较小,传输大小限制在64K以下,不需要建立连接。
Java简单使用UDP:
DatagramSocket udpClient = new DatagramSocket() 端口随机 客户端
DatagramSocket udpSocket = new DatagramSocket(port) 指定端口 :服务端
客户端向服务器端发送一个数据,服务端原样返回
client端代码:
package tcpandudp.udpexample; import java.io.IOException; import java.net.*; import java.util.Scanner; /** * @ClassName UdpClient * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/12. */ public class UdpClient { public static void main(String[] args) { /** * 键盘输入 */ Scanner scanner = new Scanner(System.in); /** * 构建客户端UDP Socket 端口随机 从键盘获取数据发送 * 初始化要发给服务端的数据包 */ try (DatagramSocket udpClient = new DatagramSocket()){ /** * 初始化要发给服务端的数据包 */ DatagramPacket outputPacket = new DatagramPacket(new byte[0],0, InetAddress.getByName("127.0.0.1"),2233); //返回数据的字节数组 byte[] inBuffer = new byte[4096]; /** * 循环发送并获取返回数据 */ while (scanner.hasNextLine()){ //获取键盘输入 String line = scanner.nextLine(); //将初始化的数据包加入数据 outputPacket.setData(line.getBytes()); // 使用socket 发送数据 udpClient.send(outputPacket); //返回数据包构建 DatagramPacket inputPacket = new DatagramPacket(inBuffer,inBuffer.length); //返回数据写入inputPacket包 udpClient.receive(inputPacket); System.out.println("收到返回数据:" + new String(inputPacket.getData(),0,inputPacket.getLength())); } } catch (SocketException | UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
server端代码:
package tcpandudp.udpexample; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /** * @ClassName UDPServer * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/12. */ public class UDPServer { public static void main(String[] args) { /** * 定义UDP服务端监听的端口 */ int port = 2233; /** * 构造一个接受UDP数据的包 */ byte[] inBuffer = new byte[4096]; DatagramPacket inPacket = new DatagramPacket(inBuffer,inBuffer.length); /** * 构建socket 接受数据放到UDP包中解析, * udpSocket 实例放到try()语句中自动管理,报错后自动close() */ try (DatagramSocket udpSocket = new DatagramSocket(port)){ /** * 获取客户端数据 */ while (true){ //获取客户端数据,装到inPacket包中 udpSocket.receive(inPacket); System.out.println(inBuffer == inPacket.getData()); //测试包中的数组和定义的inBuffer数组是否是同一个对象 /** * 将收到的包中字节(inPacket.getData())转换为字符串 */ System.out.println("收到:" + new String(inPacket.getData(),0,inBuffer.length)); /** * 构建发送包 */ DatagramPacket outPacket = new DatagramPacket(inPacket.getData(),inPacket.getLength(),inPacket.getSocketAddress()); //发送数据 udpSocket.send(outPacket); } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
MulticastSocket基于UDP协议实现多点广播:
DatagramSocket只允许数据报发送给指定的目标地址,而MulticastSocket可以将数据报以广播方式发送到多个客户端。若要使用多点广播,需要让一个数据报标有一组目标主地址,当数据报发出后,整个组的所有主机都能收到该数据报文,多点广播(或多点发送)实现了将单一信息发送到多个接收者的广播。思想是设置一组特殊网络地址作为多点广播地址,每一个多点广播地址都被看做一个组,当客户端需要发送、接收广播信息时,加入到该组即可。
IP协议为多点广播提供了这批特殊的IP地址,这些IP地址的范围是 224.0.0.0 到 239.255.255.255
多点广播的示意图如下:
客户端控制台输入内容,所有的加入本组的客户端都能收到消息:
package tcpandudp.udpexample; import java.io.IOException; import java.io.PipedReader; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.util.Scanner; /** * @ClassName MulticastSocketServerAndClient * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/12. */ public class MulticastSocketClient { /** * 多点广播的IP:224.0.0.0 到 239.255.255.255 */ private static final String BROAD_CAST_IP = "230.1.1.1"; /** * 多点广播的端口任意 */ private static final int BROAD_CAST_PORT = 30000; private void start(){ /** * 创建广播socket */ try (MulticastSocket multicastSocket = new MulticastSocket(BROAD_CAST_PORT); Scanner scanner = new Scanner(System.in); ){ /** * 构建IP地址实例 * 初始化Socket 加入监听广播组地址(接收组内消息,向组内发送消息) */ InetAddress broadcastAddr = InetAddress.getByName(BROAD_CAST_IP); multicastSocket.joinGroup(broadcastAddr); /** * 启动一个线程接收广播数据 */ new Thread(){ @Override public void run() { /** * 构建接收数据的UDP包 */ byte[] inBuffer = new byte[4096]; DatagramPacket inPacket = new DatagramPacket(inBuffer,0,inBuffer.length); /** * 获取到数据输出 */ while (true){ try { multicastSocket.receive(inPacket); System.out.println("收到:" + new String(inPacket.getData(),0,inPacket.getLength())); } catch (IOException e) { e.printStackTrace(); } } } }.start(); /** * 构建要发送的UDP数据包 * 主线程获取命令行输入,发送广播 */ DatagramPacket outPacket = new DatagramPacket(new byte[0],0, broadcastAddr,BROAD_CAST_PORT); while (scanner.hasNextLine()){ /** * 获取输入内容字节,加到包中 * 然后发送出去 */ outPacket.setData(scanner.nextLine().getBytes()); multicastSocket.send(outPacket); } } catch (IOException e) { e.printStackTrace(); } } /** * 程序入口 */ public static void main(String[] args) { new MulticastSocketClient().start(); } }
posted on 2021-05-14 23:01 zhangmingda 阅读(799) 评论(0) 编辑 收藏 举报