UDP套接字

UDP实际上实现了两个功能:
1、在IP之上补充了端口的概念
2、对数据传输过程进行错误检测,并抛弃损坏的数据

UDP使用前,不需要连接,不保证信息一定成功送达,不保证发送顺序和接收顺序(所以使用UDP需要处理信息丢失和顺序重排)。

根据以上特性,UDP使用效率比TCP高。因为不需要创建连接,不需要像TCP一样保证可靠的字节流。

Java使用 DatagramSocket 来发送和接收数据 、DatagramPacket 为数据载体。

具体方法参考:

1
2
java.net.DatagramSocket.receive(DatagramPacket) //接收数据
java.net.DatagramSocket.send(DatagramPacket) //发送数据

receive一旦完成,会重置DatagramPacket的缓冲区长度为实际接收的数据的长度。
所以,如果再次使用同一个DatagramPacket实例接收数据时,要确保长度足够,否则收到的数据会被截断。
(原文:This method blocks until a datagram is received. The length field of the datagram packet object contains the length of the received message. If the message is longer than the packet’s length, the message is truncated.)

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.fenxiangz.socket.udp;
import java.io.*;
import java.net.*;
class UDPServer{
public static void main(String[] args)throws IOException{
DatagramSocket server = new DatagramSocket(8520);
byte[] recvBuf = new byte[100];
DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
server.receive(recvPacket);
String recvStr = new String(recvPacket.getData(), 0, recvPacket.getLength());
System.out.println("Hello World!" + recvStr);
int port = recvPacket.getPort();
InetAddress addr = recvPacket.getAddress();
String sendStr = "Hello ! I'm Server";
byte[] sendBuf;
sendBuf = sendStr.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port);
server.send(sendPacket);
server.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.fenxiangz.socket.udp;
import java.io.*;
import java.net.*;
class UDPClient{
public static void main(String[] args)throws IOException{
DatagramSocket client = new DatagramSocket();
String sendStr = "Hello! I'm Client";
byte[] sendBuf;
sendBuf = sendStr.getBytes();
InetAddress addr = InetAddress.getByName("127.0.0.1");
int port = 8520;
DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port);
client.send(sendPacket);
byte[] recvBuf = new byte[100];
DatagramPacket recvPacket = new DatagramPacket(recvBuf , recvBuf.length);
client.receive(recvPacket);
String recvStr = new String(recvPacket.getData() , 0 ,recvPacket.getLength());
System.out.println("收到:" + recvStr);
client.close();
}
}

connect方法说明:

可以看一下DatagramSocket还有一个connect方法:

1
java.net.DatagramSocket.connect(InetAddress address, int port)

在例子中,并没有调用connect方法。看一下文档对connect的描述:

Connects the socket to a remote address for this socket. When a
socket is connected to a remote address, packets may only be
sent to or received from that address. By default a datagram
socket is not connected.

一旦调用了connect,则这个DatagramSocket只能与目标SocketAddress通信(发送和接收)。
绑定了SocketAddress的DatagramSocket调用send或receive方法,如果如果地址不存在或不可达,则有可能会抛出异常:PortUnreachableException,是可能,不是一定抛出(不保证:原文:Note, there is no guarantee that the exception will be thrown.)。