Fork me on GitHub

UDP

注意:所有文章除特别说明外,转载请注明出处.

UDP

[TOC]

基于UDP协议的Socket编程

1. 基于UDP协议的Socket网络编程步骤

1.利用 DatagramPacket 对象封装数据报

    DatagramPacket类将数据字节填充到UDP数据包中,是数据报

2.利用 DatagramSocket 对象发送数据报

    DatagramSocket类收发数据报。

3.利用 DatagramSocket 对象接收数据报

4.利用 DatagramPacket 对象处理数据报

提示:DatagramPacket类,封装了数据报的数据、数据长度、目标地址和目标端口。DatagramSocket类,接收和发送DatagramPacket对象封装好的数据报。

提示:UDP的这种职责划分与TCP使用的Socket与ServerSocket不一样。1. UDP没有两台主机间唯一连接的概念。一个Socket会收发所有指向指定端口的数据,不需要知道对方是哪一个远程主机。一个 DatagramSocket 可以从多个独立主机收发数据。与TCP不一样的是,UDP的Socket不专用与一个连接。

2. 基于UDP协议的Socket通信

这一过程可以类比与快递礼物的收发过程,礼物-数据,包裹-DatagramPacket,快递点-DatagramSocket,寄礼物-send(),收礼物-receive()。

2.1 基于UDP协议的Socket通信(服务端)
package cn.edu.xidian.see.*.Inet.UDPSocket;

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

public class LogicServicer {
    public static void main(String[] args) {
        byte[] infos = new byte[1024];
        DatagramPacket dp = new DatagramPacket(infos,infos.length);
        //快递点
        DatagramSocket socket=null;
        try {
            socket = new DatagramSocket(5000);
            //在快递点取礼物
            socket.receive(dp);
            //拆礼物
            String info = new String(dp.getData(),0,dp.getData().length);
            System.out.println("客户端说:"+info);
            //给客户端一个响应
            String reply ="一件羽绒服";
            byte[] reply2 = reply.getBytes();
            //客户端地址
            SocketAddress sa = dp.getSocketAddress();
            //打开一个包裹
            DatagramPacket dp1 = new DatagramPacket(reply2,reply2.length,sa);
            //寄出去
            socket.send(dp1);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            socket.close();
        }
    }
}
2.2 基于UDP协议的Socket通信(客户端)
package cn.edu.xidian.see.*.Inet.UDPSocket;

import java.io.IOException;
import java.net.*;

public class LogicClient {
    public static void main(String[] args) {
        //买礼物
        String info="心形巧克力!";
        byte[] infos = info.getBytes();
        //对方地址和邮编(端口号)
        InetAddress ia;
        //快递点
        DatagramSocket socket = null;
        try {
            //localhost = 127.0.0.1 回环地址
            ia = InetAddress.getByName("localhost");
            //包裹包装礼物
            DatagramPacket dp = new DatagramPacket(infos, infos.length, ia, 5000);
            socket = new DatagramSocket();
            //通过快递点往外寄出礼物
            try {
                socket.send(dp);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //接收服务器的响应
            byte[] replys = new byte[1024];
            DatagramPacket dp1 = new DatagramPacket(replys,replys.length);
            socket.receive(dp1);
            String reply = new String(dp1.getData(),0,dp.getData().length);
            System.out.println("服务器的响应:"+reply);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            socket.close();
        }
    }
}

DatagramPacket 类

DatagramSocket 类

DatagramChannel

DatagramChannel类用与非阻塞UDP应用程序,与SocketChannel和ServerSocketChannel用于非阻塞TCP应用程序一样。类似于SocketChannel和ServerSocketChannel,DatagramChannel是SelectableChannel的子类,可以注册到一个Selector。

在UDP中,一个数据报Socket可以处理多个客户端的输入和输出请求。而DatagramChannel类所增加的就是能够以非阻塞的方式做到这一点。这样的话如果网络没有立即准备好收发数据,这些方法可以迅速返回。

1. 打开socket

//1. 创建通道
DatagramChannel channel = DatagramChannel.open();

//2. 监听通道的地址
SocketAddress address = new InetSocketAddress(3122);

//3. 监听连接
DatagramSocket socket = channel.socket();

//4. 绑定端口
socket.bind(address);

2. 接收

receive()方法从通道读取一个数据报包,放在一个ByteBuffer中。返回这个包的主机地址。

public SocketAddress receive(ByteBuffer dst) throws IOException;

如果通道是阻塞的话,上面方法在读取到包之前不会返回。如果通道是非阻塞的话,没有包可以在读取的情况下该方法立即返回null。

3. 发送

send()方法将一个数据报从ByteBuffer写入通道,要写到第二个参数指定的地址。

public int send(ByteBuffer src, SocketAddress target) throws IOException;

注意:如果希望向多个客户端发送相同的数据,可以重用源ByteBuffer。不过在之前需要将其回倒(rewind/flip())。

4. 连接

我们在打开一个数据通道之后,能够通过connect()方法将它连接到一个特定的远程地址。

SocketAddress address = new InetSocketAddress();
channel.connect(address);

5. 读取

6. 写入

选择TCP通道与选择数据报通道之间有一个主要区别。因为数据报通道实际上是无连接的(尽管有connect()方法),所以需要注意传输何时结束何时关闭。

7. 关闭

在结束操作时关闭通道,释放其占用的端口和其它资源。

本文标题:UDP

文章作者:Bangjin-Hu

发布时间:2019年10月15日 - 09:22:26

最后更新:2020年03月30日 - 07:58:37

原始链接:http://bangjinhu.github.io/undefined/UDP/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Bangjin-Hu wechat
欢迎扫码关注微信公众号,订阅我的微信公众号.
坚持原创技术分享,您的支持是我创作的动力.