UDP协议

   UDP协议提供的服务不同于TCP协议的端到端服务,它是面向非连接的,属不可靠协议,UDP套接字在使用前不需要进行连接。实际上,UDP协议实现了两个功能:

    1)在IP协议的基础上添加了端口;

    2)对传输过程中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。

UDP的Java支持

    Java通过DatagramPacket类和DatagramSocket类来使用UDP套接字,客户端和服务器端都通过DatagramSocket的send()方法和receive()方法来发送和接收数据,用DatagramPacket来包装需要发送或者接收到的数据。发送信息时,Java创建一个包含待发送信息的DatagramPacket实例,并将其作为参数传递给DatagramSocket实例的send()方法;接收信息时,Java程序首先创建一个DatagramPacket实例,该实例预先分配了一些空间,并将接收到的信息存放在该空间中,然后把该实例作为参数传递给DatagramSocket实例的receive()方法。在创建DatagramPacket实例时,要注意:如果该实例用来包装待接收的数据,则不指定数据来源的远程主机和端口,只需指定一个缓存数据的byte数组即可(在调用receive()方法接收到数据后,源地址和端口等信息会自动包含在DatagramPacket实例中),而如果该实例用来包装待发送的数据,则要指定要发送到的目的主机和端口。

 

 

UDP的通信建立的步骤

 

    UDP客户端首先向被动等待联系的服务器发送一个数据报文。一个典型的UDP客户端要经过下面三步操作:

    1、创建一个DatagramSocket实例,可以有选择地对本地地址和端口号进行设置,如果设置了端口号,则客户端会在该端口号上监听从服务器端发送来的数据;

    2、使用DatagramSocket实例的send()和receive()方法来发送和接收DatagramPacket实例,进行通信;

    3、通信完成后,调用DatagramSocket实例的close()方法来关闭该套接字。

 

   由于UDP是无连接的,因此UDP服务端不需要等待客户端的请求以建立连接。另外,UDP服务器为所有通信使用同一套接字,这点与TCP服务器不同,TCP服务器则为每个成功返回的accept()方法创建一个新的套接字。一个典型的UDP服务端要经过下面三步操作:

    1、创建一个DatagramSocket实例,指定本地端口号,并可以有选择地指定本地地址,此时,服务器已经准备好从任何客户端接收数据报文;

    2、使用DatagramSocket实例的receive()方法接收一个DatagramPacket实例,当receive()方法返回时,数据报文就包含了客户端的地址,这样就知道了回复信息应该发送到什么地方;

    3、使用DatagramSocket实例的send()方法向服务器端返回DatagramPacket实例。

 

                             Java UDP Socket编程

     这里有一点需要注意:

UDP程序在receive()方法处阻塞,直到收到一个数据报文或等待超时。由于UDP协议是不可靠协议,如果没有收到DatagramPacket,那么程序将会一直阻塞在receive()方法处,这样客户端将永远都接收不到服务器端发送回来的数据,但是又没有任何提示。为了避免这个问题,我们在客户端使用DatagramSocket类的setSoTimeout()方法来制定receive()方法的最长阻塞时间,并指定重发数据报的次数,如果每次阻塞都超时,并且重发次数达到了设置的上限,则关闭客户端。

下面给出一个客户端服务端UDP通信的Demo(没有用多线程),该客户端在本地2222端口监听接收到的数据,并将字符串"Hello UDPserver"发送到本地服务器的3222端口,服务端在本地3222端口监听接收到的数据,如果接收到数据,则返回字符串"Hello UDPclient"到该客户端的2222端口。在客户端,由于程序可能会一直阻塞在receive()方法处,因此这里我们在客户端用DatagramSocket实例的setSoTimeout()方法来指定receive()的最长阻塞时间TIMEOUT ,并设置重发数据的次数MAXNUM ,如果最终依然没有接收到从服务端发送回来的数据,我们就关闭客户端。

 

Java UDP Socket编程
 1 import java.io.IOException;
 2 import java.io.InterruptedIOException;
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 
 7 public class UdpClient {
 8     private static final int MAXNUM = 5; // 设置重发数据的最多次数
 9     private static final int TIMEOUT = 5000;  //设置接收数据的超时时间
10     private static final int CLIENT_PORT = 2222;
11     private static final int SERVER_PORT = 3222;
12     private static final int REV_SIZE = 1024; //接收数据的存储空间大小
13     
14     public static void main(String[] args) throws IOException {
15         String str_send = "Hello UDPserver"; //要发送的字串
16         byte[] buf_rev = new byte[REV_SIZE];     //要接收的存储空间
17         
18         /*第一步 实例化DatagramSocket*/
19         DatagramSocket mSoc = new DatagramSocket(CLIENT_PORT);
20         mSoc.setSoTimeout(TIMEOUT);              //设置接收数据时阻塞的最长时间  
21         
22         /*第二步 实例化用于发送的DatagramPacket和用于接收的DatagramPacket*/
23         InetAddress inetAddress = InetAddress.getLocalHost();
24         DatagramPacket data_send = new DatagramPacket(str_send.getBytes(),
25                 str_send.length(), inetAddress, SERVER_PORT);
26         
27         DatagramPacket data_rev = new DatagramPacket(buf_rev, REV_SIZE);
28 
29         
30         /*第三步 DatagramPacket send发送数据,receive接收数据*/
31         int send_count = 0; // 重发数据的次数
32         boolean revResponse = false; // 是否接收到数据的标志位
33         while (!revResponse && send_count < MAXNUM) {
34             try {
35                 mSoc.send(data_send); //发送数据
36                 mSoc.receive(data_rev);//接收数据
37                 if (!data_rev.getAddress().getHostAddress()
38                         .equals(InetAddress.getLocalHost().getHostAddress())) {
39                     throw new IOException(
40                             "Received packet from an umknown source");
41                 }
42                 revResponse = true;
43             } catch (InterruptedIOException e) {
44                 // 如果接收数据时阻塞超时,重发并减少一次重发的次数
45                 send_count += 1;
46                 System.out.println("Time out," + (MAXNUM - send_count)
47                         + " more tries...");
48             }
49         }
50         if (revResponse) {
51             // 如果收到数据,则打印出来
52             System.out.println("client received data from server:");
53             String str_receive = new String(data_rev.getData(), 0,
54                     data_rev.getLength())
55                     + " from "
56                     + data_rev.getAddress().getHostAddress()
57                     + ":"
58                     + data_rev.getPort();
59             System.out.println(str_receive);
60             // 由于dp_receive在接收了数据之后,其内部消息长度值会变为实际接收的消息的字节数,
61             // 所以这里要将dp_receive的内部消息长度重新置为1024
62             data_rev.setLength(REV_SIZE);
63         } else {
64             // 如果重发MAXNUM次数据后,仍未获得服务器发送回来的数据,则打印如下信息
65             System.out.println("No response -- give up.");
66         }
67         
68         /*第四步 关闭DatagramPacket*/
69         mSoc.close();
70     }
71 
72 }
Java UDP Socket编程

相关文章:

  • 2021-05-02
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-02-14
  • 2022-01-09
猜你喜欢
  • 2022-12-23
  • 2021-10-13
  • 2022-01-08
  • 2021-06-24
  • 2022-12-23
相关资源
相似解决方案