在本 Java 网络编程教程中,您将学习如何编写基于 UDP 协议的客户端/服务器应用程序。
首先,让我们看看 Java Network API 是如何设计来支持使用 UDP 的网络应用程序开发的。
DatagramPacket 和DatagramSocket是用于实现 UDP 客户端/服务器应用程序的两个主要类。DatagramPacket是一个数据容器,DatagramSocket是一种发送和接收DatagramPacket的机制。
1. 数据报包
在 UDP 的术语中,传输的数据被封装在一个称为数据报的单元中。数据报是通过网络发送的一个独立的、自包含的消息,其到达、到达时间和内容都没有保证。而在 Java 中,DatagramPacket代表一个数据报。
您可以使用以下构造函数之一创建DatagramPacket对象:
- DatagramPacket(byte[] buf, int length)
- DatagramPacket(byte[] buf, int 长度, InetAddress 地址, int 端口)
如您所见,数据必须采用字节数组的形式。第一个构造函数用于创建要接收的DatagramPacket。
第二个构造函数创建了一个要发送的DatagramPacket,所以需要指定目的主机的地址和端口号。
参数 length 指定要使用的字节数组中的数据量,通常是数组的长度(buf.length)。
还有其他构造函数允许您指定字节数组中的偏移量,以及使用SocketAddress:
- DatagramPacket(byte[] buf, int offset, int length)
- DatagramPacket(byte[] buf, int offset, int length, SocketAddress 地址)
此外,DatagramPacket为地址、数据和端口号提供了 setter 和 getter 方法。有关完整的详细信息,请参阅其DatagramPacket Javadoc。
2. 数据报套接字
您使用DatagramSocket发送和接收DatagramPacket。DatagramSocket表示网络中两台计算机之间的 UDP 连接。
在 Java 中,我们对客户端和服务器都使用DatagramSocket。客户端和服务器没有单独的类,如 TCP 套接字。
因此,您可以使用以下构造函数之一创建一个DatagramSocket对象来建立用于发送和接收数据报的 UDP 连接:
- 数据报套接字()
- DatagramSocket(int 端口)
- DatagramSocket(int 端口,InetAddress 梯形图)
无参数构造函数用于创建绑定到任意端口号的客户端。第二个构造函数用于创建绑定到特定端口号的服务器,以便客户端知道如何连接。
第三个构造函数将服务器绑定到指定的 IP 地址(以防计算机有多个 IP 地址)。
如果无法打开套接字,或者套接字无法绑定到指定的端口或地址,则这些构造函数可以抛出SocketException。所以你已经捕获或重新抛出这个已检查的异常。
DatagramSocket的关键方法包括:
- send (DatagramPacket p):发送数据报包。
- 接收(DatagramPacket p):接收数据报包。
- setSoTimeout (int timeout):以毫秒为单位设置超时时间,限制接收数据时的等待时间。如果超时到期,则会引发SocketTimeoutException。
- close ():关闭套接字。
这些方法可以抛出IOException、PortUnreachableException、SocketTimeoutException ……所以你必须捕捉或重新抛出它们。有关 完整的详细信息,请参阅 DatagramSocket Javadoc。
现在,让我们看看一些运行中的示例程序。
3. Java UDP 客户端示例
我们将为一个客户端程序编写代码,该程序从实现每日报价 (QOTD) 服务(一种 Internet 标准)的服务器请求报价。以下代码片段将DatagramPacket发送到由主机名和端口指定的服务器:
1 2 3 4 5 6 7 8 9 10 | String hostname = "djxmmx.net" ; int port = 17 ; InetAddress address = InetAddress.getByName(hostname); DatagramSocket socket = new DatagramSocket(); byte [] buffer = new byte [ 512 ]; DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, port); socket.send(request); |
如您所见,缓冲区没有数据,因为 QOTD 服务不需要客户端发送任何特定消息。并且您必须在DatagramPacket 中指定服务器的地址和端口。所以这段代码只是向服务器发送一个信号,暗示“嘿,我想从你那里得到一个报价”。
下面的代码片段从服务器接收一个DatagramPacket:
1 2 3 4 5 6 | DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); String quote = new String(buffer, 0 , response.getLength()); System.out.println(quote); |
如您所见,一旦套接字打开,接收数据包非常简单。并且代码将字节数组转换为以可读格式打印的字符串。
这是完整客户端程序的代码,它参数化主机名和端口号,处理异常并每 10 秒从服务器获取报价:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import java.io.*; import java.net.*; /** * This program demonstrates how to implement a UDP client program. * * * @author www.codejava.net */ public class QuoteClient { public static void main(String[] args) { if (args.length < 2 ) { System.out.println( "Syntax: QuoteClient <hostname> <port>" ); return ; } String hostname = args[ 0 ]; int port = Integer.parseInt(args[ 1 ]); try { InetAddress address = InetAddress.getByName(hostname); DatagramSocket socket = new DatagramSocket(); while ( true ) { DatagramPacket request = new DatagramPacket( new byte [ 1 ], 1 , address, port); socket.send(request); byte [] buffer = new byte [ 512 ]; DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); String quote = new String(buffer, 0 , response.getLength()); System.out.println(quote); System.out.println(); Thread.sleep( 10000 ); } } catch (SocketTimeoutException ex) { System.out.println( "Timeout error: " + ex.getMessage()); ex.printStackTrace(); } catch (IOException ex) { System.out.println( "Client error: " + ex.getMessage()); ex.printStackTrace(); } catch (InterruptedException ex) { ex.printStackTrace(); } } } |
要测试此客户端程序,请键入以下命令:
1 | java QuoteClient djxmmx.net 17 |
djxmmx.net是我们可以使用的公共QOTD服务器,17是为QOTD服务预留的端口号。
你会看到这样的输出:
1 2 3 4 5 6 7 | "When a stupid man is doing something he is ashamed of, he always declares that it is his duty." George Bernard Shaw (1856-1950) "Oh the nerves, the nerves; the mysteries of this machine called man! Oh the little that unhinges it, poor creatures that we are!" Charles Dickens (1812-70) In Heaven an angel is nobody in particular." George Bernard Shaw (1856-1950) |
如果您自己测试这个程序,您可能会看到不同的引号,因为服务器返回随机引号。按 Ctrl + C 终止程序。
4. Java UDP 服务器示例
下面的示例程序演示了如何为上述客户端实现服务器。以下代码创建一个 UDP 服务器,监听端口 17 并等待客户端的请求:
1 2 3 4 5 6 | DatagramSocket socket = new DatagramSocket( 17 ); byte [] buffer = new byte [ 256 ]; DatagramPacket request = new DatagramPacket(buffer, buffer.length); socket.receive(request); |
的接收() ,直到接收到一个数据报的方法块。下面的代码向客户端发送一个DatagramPacket:
1 2 3 4 5 6 7 8 | InetAddress clientAddress = request.getAddress(); int clientPort = request.getPort(); String data = "Message from server" ; buffer = data.getBytes(); DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort); socket.send(response); |
如您所见,服务器还需要知道客户端的地址和端口才能发送DatagramPacket。该信息可以从之前从客户端接收到的DatagramPacket 中获得。并且 String 被转换为一个字节数组,然后可以将其包装在DatagramPacket 中。
下面是一个功能齐全的服务器程序,它从文本文件中读取报价,并为每个客户端的请求发送一个随机报价。引用文件和端口号作为程序的参数给出。这是代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | import java.io.*; import java.net.*; import java.util.*; /** * This program demonstrates how to implement a UDP server program. * * * @author www.codejava.net */ public class QuoteServer { private DatagramSocket socket; private List<String> listQuotes = new ArrayList<String>(); private Random random; public QuoteServer( int port) throws SocketException { socket = new DatagramSocket(port); random = new Random(); } public static void main(String[] args) { if (args.length < 2 ) { System.out.println( "Syntax: QuoteServer <file> <port>" ); return ; } String quoteFile = args[ 0 ]; int port = Integer.parseInt(args[ 1 ]); try { QuoteServer server = new QuoteServer(port); server.loadQuotesFromFile(quoteFile); server.service(); } catch (SocketException ex) { System.out.println( "Socket error: " + ex.getMessage()); } catch (IOException ex) { System.out.println( "I/O error: " + ex.getMessage()); } } private void service() throws IOException { while ( true ) { DatagramPacket request = new DatagramPacket( new byte [ 1 ], 1 ); socket.receive(request); String quote = getRandomQuote(); byte [] buffer = quote.getBytes(); InetAddress clientAddress = request.getAddress(); int clientPort = request.getPort(); DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort); socket.send(response); } } private void loadQuotesFromFile(String quoteFile) throws IOException { BufferedReader reader = new BufferedReader( new FileReader(quoteFile)); String aQuote; while ((aQuote = reader.readLine()) != null ) { listQuotes.add(aQuote); } reader.close(); } private String getRandomQuote() { int randomIndex = random.nextInt(listQuotes.size()); String randomQuote = listQuotes.get(randomIndex); return randomQuote; } } |
假设我们有一个Quotes.txt文件,其中包含以下内容(每个引号都在一行中):
1 2 3 4 5 | Whether you think you can or you think you can't, you're right - Henry Ford There are no traffic jams along the extra mile - Roger Staubach Build your own dreams, or someone else will hire you to build theirs - Farrah Gray What you do today can improve all your tomorrows - Ralph Marston Remember that not getting what you want is sometimes a wonderful stroke of luck - Dalai Lama |
键入以下命令以运行服务器程序:
1 | java QuoteServer Quotes.txt 17 |
并运行客户端程序(在同一台计算机上):
1 | java QuoteClient localhost 17 |
客户端和服务器都在无限循环中运行,因此您必须按 Ctrl + C 终止。
这就是关于如何开发依赖 UDP 协议的网络客户端/服务器应用程序的课程。基于这些知识,您可以开发通过 UDP 与服务器通信的客户端程序,并开发您自己的 UDP 客户端/服务器应用程序。
API参考:
相关 Java 网络教程:
今天的文章Java UDP 客户端服务器程序示例分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/25695.html