Java UDP 客户端服务器程序示例
在本 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參考:
- 數據報包 Javadoc
- 數據報套接字 Javadoc
?
相關 Java 網絡教程:
- Java InetAddress 示例
- Java 套接字客戶端示例 (TCP/IP)
- Java 套接字服務器示例 (TCP/IP)
總結
以上是生活随笔為你收集整理的Java UDP 客户端服务器程序示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [css] word-wrap、wor
- 下一篇: 【雕刻机】使用雕刻机雕刻PCB