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
多点广播的示意图如下:
0
客户端控制台输入内容,所有的加入本组的客户端都能收到消息:
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  阅读(574)  评论(0编辑  收藏  举报

导航