本文翻译自国外网站的一篇文章,觉得讲的简单易懂,遂翻译出来。一是共享,而是练练手。
原文:A Guide To UDP In Java
1.综述
在本指南中,我们探讨的是Java中有关UDP网络通信的知识。
UDP是一种网络通信协议,可以在网络中传输独立的数据包,但是UDP协议不保证传输的有序性和可靠性。UDP是面向无连接,不可靠传输的协议。
尽管大部分的网络通信都是通过TCP(有连接,可靠)来进行的,但接下来我们将要讨论UDP的应用场景。
2.为什么使用UDP
UDP与常见的TCP有很大不同。但是在考虑到UDP的表面缺点之前,更重要的是理解缺乏开销要比TCP快很多。
除了速度,我们还应记住几种通信,如不需要可靠性,但是要求低延迟。视频应用就是一个很好的例子,通过UDP而不是TCP传输。
3.创建UDP应用
创建UDP应用与创建TCP类似,唯一的区别就是我们不需要建立客户端和服务器点对点之间的连接。
设置也很简单。Java自带支持UDP开发的工具包,实在java.net包中。因此,要通过UDP进行网络操作,我们只需要从java.net包中导入所需类:java.net.DatagramSocket 和 java.net.DatagramPacket.
首先,我们建立一个应答服务器,该服务器可以发消息给他的客户端发送任何返回消息。应答客户端仅可以向服务器发送任意消息。最后,测试应用程序确保一起工作没问题。
首先,我们将构建一个回送服务器,发送回发送给它的任何消息,然后是一个只向服务器发送任意消息的回显客户端,最后,我们将测试应用程序以确保一切正常。
4.服务器
在UDP通信中,单条消息是被装在DatagramPacket中通过DatagramSocket被发送出去的。
我们先建立一个简单的服务端。
/**
* 该服务程序在收到消息后,从DatagramPacket中取出客户端地址和端
*口号,再回一条消息
*/
public class EchoServer extends Thread {
private DatagramSocket socket;
private boolean running;
private byte[] buf = new byte[256];
public EchoServer() {
socket = new DatagramSocket(4445);
}
public void run() {
running = true;
while (running) {
DatagramPacket packet
= new DatagramPacket(buf, buf.length);
socket.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(buf, buf.length, address, port);
String received
= new String(packet.getData(), 0, packet.getLength());
if (received.equals("end")) {
running = false;
continue;
}
socket.send(packet);
}
socket.close();
}
}
我们创建了一个发送数据包的全局的DatagramSocket,一个用来装消息的byte数组和一个状态变量。
为了简单,服务器继承自线程Thread,因此可以在run()方法中做需要的工作。
在run方法内部创建了一个while循环,除非running=false或遇到某些错误或者收到来自客户端的终止信息。
在循环顶部,实例化了一个DatagramPacket用来接受消息。
接下来,调用了socket的receive()方法。该方法是阻塞式的,直到收到消息。收到的消息会存放在DatagramPacket中的一个byte数组中。
收到消息后,从收到的DatagramPacket获取客户端的地址和端口号,因为我们需要发送返回消息。
下一步,创建向客户端发送消息的DatagramPacket。注意与收到的DatagramPacket的区别。这个也需要发送的地址和端口号。
5.客户端
现在,我们为该服务器创建一个简单的客户端程序。
public class EchoClient {
private DatagramSocket socket;
private InetAddress address;
private byte[] buf;
public EchoClient() {
socket = new DatagramSocket();
address = InetAddress.getByName("localhost");
}
public String sendEcho(String msg) {
buf = msg.getBytes();
DatagramPacket packet
= new DatagramPacket(buf, buf.length, address, 4445);
socket.send(packet);
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(
packet.getData(), 0, packet.getLength());
return received;
}
public void close() {
socket.close();
}
}
客户端代码与服务器的不同。我们有全局的DatagramSocket和服务器的地址。在构造器内部实例化这些变量。
我们有一个独立的方法用来向服务器发送消息和接收服务器返回的消息。
首先需要将String类型的消息转化为byte数组,然后创建一个DatagramPacket用来发送消息。
下一步,发送消息。然后立即将DatagramPacket转化为一个接收的packet。
当服务器返回消息时,将收到的byte数组转化为string并返回。
6.测试
在 UDPTest.java类中,创建了一个简单的测试用来检查我们服务器和客户端的应用程序。
public class UDPTest {
EchoClient client;
@Before
public void setup(){
new EchoServer().start();
client = new EchoClient();
}
@Test
public void whenCanSendAndReceivePacket_thenCorrect() {
String echo = client.sendEcho("hello server");
assertEquals("hello server", echo);
echo = client.sendEcho("server is working");
assertFalse(echo.equals("hello server"));
}
@After
public void tearDown() {
client.sendEcho("end");
client.close();
}
}
在setup()方法中,启动服务并创建了一个客户端。在tearDown()方法中,向服务器发送一个终止消息以便能够关闭客户端的同时关闭服务器。
7.总结
在本文中,了解了UDP协议并成功创建了客户端-服务器应用程序,通过UDP实现了通信。
获取示例源码 GitHub project.