概述:
UDP协议提供了一种不同于TCP协议的端到端服务。实际上UDP协议只实现两个功能:
1)在IP协议的基础上添加了另一层地址(端口),
2)对数据传输过程中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。由于其简单性,UDP套接字具有一些与我们之前所看到的TCP套接字不同的特征。例如,UDP套接字在使用前不需要进行连接。TCP协议与电话通信相似,而UDP协议则与邮件通信相似:你寄包裹或信件时不需要进行"连接",但是你得为每个包裹和信件指定目的地址。类似的,每条信息(即数据报文,datagram)负载了自己的地址信息,并与其他信息相互独立。在接收信息时,UDP套接字扮演的角色就像是一个信箱,从不同地址发送来的信件和包裹都可以放到里面。一旦被创建,UDP套接字就可以用来连续地向不同的地址发送信息,或从任何地址接收信息。
1.API了解
DatagramPacket:创建
DatagramPacket(byte[ ] data, int length)
DatagramPacket(byte[ ] data, int offset, int length)
DatagramPacket(byte[ ] data, int length, InetAddress remoteAddr, int remotePort)
DatagramPacket(byte[ ] data, int offset, int length, InetAddress remoteAddr, int remotePort)
DatagramPacket(byte[ ] data, int length, SocketAddress sockAddr) DatagramPacket(byte[ ] data, int offset, int length, SocketAddress sockAddr)
DatagramPacket:地址处理
InetAddress getAddress()
void setAddress(InetAddress address)
int getPort()
void setPort(int port)
SocketAddress getSocketAddress()
void setSocketAddress(SocketAddress sockAddr)
DatagramPacket 处理数据
int getLength()
void setLength(int length)
int getOffset()
byte[ ] getData()
void setData(byte[ ] data)
void setData(byte[ ] buffer, int offset, int length)
2.UDP客户端:
UDP客户端首先向被动等待联系的服务器端发送一个数据报文。一个典型的UDP客户端主要执行以下三步:
1. 创建一个DatagramSocket实例,可以选择对本地地址和端口号进行设置。
2. 使用DatagramSocket类的send() 和 receive()方法来发送和接收DatagramPacket实例,进行通信。
3. 通信完成后,使用DatagramSocket类的close()方法来销毁该套接字。
与Socket类不同,DatagramSocket实例在创建时并不需要指定目的地址。这也是TCP协议和UDP协议的最大不同点之一。在进行数据交换前,TCP套接字必须跟特定主机和另一个端口号上的TCP套接字建立连接,之后,在连接关闭前,该套接字就只能与相连接的那个套接字通信。而UDP套接字在进行通信前则不需要建立连接,每个数据报文都可以发送到或接收于不同的目的地址。(DatagramSocket类的connect()方法确实允许指定远程地址和端口,但该功能是可选的
如果超过了指定时间仍未得到响应,客户端就会重发回馈请求。我们的回馈客户端执行以下步骤:
1. 向服务器端发送回馈字符串。
2. 在receive()方法上最多阻塞等待3秒钟,在超时前若没有收到响应,则重发请求(最多重发5次)。
3. 终止客户端。
package com.tcp.ip.chapter2;2.常用的API
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPEchoClientTimeout {
private static final int TIMEOUT = 3000;
private static final int MAXRIES = 5;
public static void main(String[] args) throws Exception {
if((args.length < 2) || (args.length > 3)) {
throw new IllegalArgumentException("Parameter(s) : <Server> <Word> [<Port>]");
}
InetAddress serverAddress = InetAddress.getByName(args[0]);
byte [] bytesToSend = args[1].getBytes();
int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7;
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(TIMEOUT);
DatagramPacket sendPacket = new DatagramPacket(bytesToSend, bytesToSend.length,serverAddress, servPort);
DatagramPacket receivePacket =new DatagramPacket(new byte[bytesToSend.length], bytesToSend.length);
//如果发送失败还要继续发
int tries = 0;
boolean receivedResponse = false;
do {
socket.send(sendPacket);
try {socket.receive(receivePacket);
if(!receivePacket.getAddress().equals(serverAddress)) {
throw new IOException("Received packet from an unknownsource");
}
receivedResponse = true;
} catch (InterruptedIOException e) {
tries +=1;
System.out.println("Timed out," + (MAXRIES-tries) + " more tries");
}
}while ((!receivedResponse) && (tries < MAXRIES));
if(receivedResponse) {
System.out.println("接受数据成功:" + new String(receivePacket.getData()));
}else {
System.out.println("接受数据失败");
}
socket.close();
}
}
DatagramSocket: 创建
DatagramSocket()
DatagramSocket(int localPort)
DatagramSocket(int localPort, InetAddress localAddr)
DatagramSocket: 连接与关闭
void connect(InetAddress remoteAddr, int remotePort)
void connect(SocketAddress remoteSockAddr)
void disconnect()
void close()
DatagramSocket: 地址处理
InetAddress getInetAddress()
int getPort()
SocketAddress getRemoteSocketAddress()
InetAddress getLocalAddress()
int getLocalPort() SocketAddress
getLocalSocketAddress()
DatagramSocket: 发送和接收
void send(DatagramPacket packet)
void receive(DatagramPacket packet)
DatagramSocket: 选项
int getSoTimeout()
void setSoTimeout(int timeoutMillis)
3.UDP服务器端
典型的UDP服务器要执行以下三步:
1. 创建一个DatagramSocket实例,指定本地端口号,并可以选择指定本地地址。此时,服务器已经准备好从任何客户端接收数据报文。
2. 使用DatagramSocket类的receive()方法来接收一个DatagramPacket实例。当receive()方法返回时,数据报文就包含了客户端的地址,这样我们就知道了回复信息应该发送到什么地方。
3. 使用DatagramSocket类的send() 和receive()方法来发送和接收DatagramPackets实例,进行通信。
package com.tcp.ip.chapter2;DatagramSocket就是像快递员,没有打电话通知你,可能第一次他去你家,你不在,他就是回去了,下一次再来,你又不在家,一直到⑤次还不在,他认为你拒收了。
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPEchoServer {
private static final int ECHOMAX = 255;
public static void main(String[] args) throws Exception {
if(args.length != 1) {
throw new IllegalArgumentException("Parameter(s): <Port>");
}
int servPort = Integer.parseInt(args[0]);
DatagramSocket socket = new DatagramSocket(servPort);
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
while (true) {
socket.receive(packet);
System.out.println("Handling client at " + packet.getAddress().getHostAddress()
+ " on port " + packet.getPort());
socket.send(packet);
packet.setLength(ECHOMAX);
}
}
}