【Java 网络编程】UDP 服务器 与 客户端持续交互 案例
文章目錄
- I UDP 交互原理
- II UDP 服務(wù)器端代碼示例
- III UDP 客戶端代碼示例
- IV 服務(wù)器 客戶端 運(yùn)行結(jié)果
I UDP 交互原理
1. UDP 單播傳輸流程 : A 給 B 發(fā)送數(shù)據(jù)包 , B 設(shè)備一定要處于監(jiān)聽(tīng) X 端口狀態(tài) , A 向 B 的 X 端口發(fā)送數(shù)據(jù)包 , B 才能收到 ; B 收到 A 的數(shù)據(jù)包后 , B 就知道了 A 的端口號(hào) Z 的信息了 , 此時(shí) B 可以向 A 的 Z 端口號(hào)發(fā)送數(shù)據(jù)包 ;
2. 局域網(wǎng)設(shè)備交互 : A 設(shè)備給局域網(wǎng)其它設(shè)備發(fā)送信息 , 并能接收到其它設(shè)備回送給 A 的信息 ;
3. 接收信息設(shè)備監(jiān)聽(tīng) X 端口 : 此時(shí) A 作為客戶端時(shí) , 服務(wù)器需要接收 A 發(fā)送的數(shù)據(jù)包 , 服務(wù)器需要監(jiān)聽(tīng)一個(gè)指定的接口 X , 那么如果 A 發(fā)送廣播消息 , 監(jiān)聽(tīng) X 端口的服務(wù)器就會(huì)收到 A 發(fā)送的消息 ;
4. A 提前監(jiān)聽(tīng)端口 Z : 如果服務(wù)器在收到消息后立刻向 A 的 Z 端口回送一個(gè)反饋信息 , 設(shè)備 A 需要在發(fā)送消息之前就監(jiān)聽(tīng) Z 端口 , 才能實(shí)現(xiàn)上述功能 ;
5. 持續(xù)交互 : A 不斷向其它設(shè)備的 X 端口發(fā)送信息 , 其它設(shè)備可以不斷反饋信息給設(shè)備 A 的 Z 端口 , 這樣就實(shí)現(xiàn)了客戶端與服務(wù)器端數(shù)據(jù)交互的功能 ;
II UDP 服務(wù)器端代碼示例
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.util.ArrayList;public class UDPServer {public static void main(String[] args){System.out.println("服務(wù)器 開(kāi)始運(yùn)行");//開(kāi)啟接收數(shù)據(jù)的線程ReceiveThread receiveThread = new ReceiveThread();receiveThread.start();}/*** 服務(wù)器端監(jiān)聽(tīng)客戶端發(fā)送的信息*/private static class ReceiveThread extends Thread{/*** 是否繼續(xù)監(jiān)聽(tīng) , 循環(huán)控制變量*/boolean isReceive = true;/*** 存儲(chǔ)發(fā)送數(shù)據(jù)的客戶端信息*/ArrayList<Client> clients = new ArrayList<>();@Overridepublic void run() {super.run();try {//I. 創(chuàng)建 DatagramSocket 對(duì)象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包接收者 , 監(jiān)聽(tīng) 8888 端口// 該 DatagramSocket 既可以接收數(shù)據(jù)包 , 也可以發(fā)送數(shù)據(jù)包DatagramSocket datagramSocket = new DatagramSocket(8888);//II. 接收 UDP 數(shù)據(jù)包 , 無(wú)限循環(huán)接收來(lái)自客戶端的信息 , 并根據(jù)不同的信息進(jìn)行不同處理while (isReceive){//2. 接收數(shù)據(jù)包使用的緩沖區(qū)byte[] receiveBuffer = new byte[256];//3. 接收 UDP 數(shù)據(jù)包使用的 DatagramPacket 對(duì)象DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);//4. 接收 UDP 數(shù)據(jù)包datagramSocket.receive(receivePacket);//5. 獲取發(fā)送端的 IP 地址String sendIP = receivePacket.getAddress().getHostAddress();//6. 獲取發(fā)送端的端口號(hào)int sendPort = receivePacket.getPort();//7. 獲取接收到的數(shù)據(jù)的長(zhǎng)度int receiveLen = receivePacket.getLength();//8. 獲取接收到的數(shù)據(jù) , 并轉(zhuǎn)為字符串String receiveData = new String(receivePacket.getData(), 0, receiveLen);//9. 打印接收到的數(shù)據(jù)包信息System.out.println("服務(wù)器 接收到 " + sendIP + " : " + sendPort + " 發(fā)送的數(shù)據(jù) : " + receiveData);//將客戶端信息發(fā)送到//III. 發(fā)送 UDP 數(shù)據(jù)包//10. 將接收到的數(shù)據(jù)長(zhǎng)度回送給發(fā)送者String response = "服務(wù)器端 收到客戶端發(fā)送的 " + receiveLen + " Byte 數(shù)據(jù)";//11. 將字符串轉(zhuǎn)為 byte[] 數(shù)組byte[] responseData = response.getBytes();//12. 創(chuàng)建發(fā)送數(shù)據(jù)包 , 需要傳入的參數(shù) 1> 數(shù)據(jù) 2> 數(shù)據(jù)長(zhǎng)度 3> 接收者的地址 4> 接收者的端口號(hào)DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length,receivePacket.getAddress(), receivePacket.getPort());//13. 將數(shù)據(jù)包發(fā)送出去datagramSocket.send(responsePacket);System.out.println("服務(wù)器 向客戶端 " + sendIP + " : " + sendPort + " 發(fā)送的數(shù)據(jù) : " + response);//退出服務(wù)器循環(huán)if("exit".equals(receiveData)){isReceive = false;}}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {System.out.println("服務(wù)器 運(yùn)行結(jié)束");}}}/*** 封裝向服務(wù)器端發(fā)送數(shù)據(jù)的客戶端信息* 主要是保存客戶端的 IP 地址和端口號(hào)*/private static class Client{String ClientIP;String ClientPort;public Client(String clientIP, String clientPort) {ClientIP = clientIP;ClientPort = clientPort;}}}
III UDP 客戶端代碼示例
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;public class UDPClient {public static void main(String[] args){try {System.out.println("客戶端 開(kāi)始運(yùn)行");//I. 創(chuàng)建 DatagramSocket 對(duì)象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包套接字 , 客戶端 ,// 監(jiān)聽(tīng) 8889 端口 , 發(fā)送和接收數(shù)據(jù)包都使用該端口DatagramSocket datagramSocket = new DatagramSocket(8889);//II. 人機(jī)交互控制臺(tái)阻塞獲取用戶輸入//1. 獲取控制臺(tái)輸入流InputStream is = System.in;//2. 該輸入流會(huì)阻塞 , 等待用戶控制臺(tái)輸入BufferedReader br = new BufferedReader(new InputStreamReader(is));// 循環(huán)控制變量 , 循環(huán)發(fā)送和接收 UDP 數(shù)據(jù)包boolean flag = true;while(flag){//3. 阻塞命令行 , 等待用戶輸入一行數(shù)據(jù), 并存入 string 對(duì)象中String string = br.readLine();//III. 向服務(wù)器發(fā)送 UDP 數(shù)據(jù)包//1. 將字符串轉(zhuǎn)為 byte[] 數(shù)組byte[] sendData = string.getBytes();//2. 創(chuàng)建發(fā)送數(shù)據(jù)包 , 需要傳入的參數(shù) 1> 數(shù)據(jù) 2> 數(shù)據(jù)長(zhǎng)度 3> 接收者的地址 4> 接收者的端口號(hào)// 向服務(wù)器端發(fā)送數(shù)據(jù) , 發(fā)送的端口是自動(dòng)分配的DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,InetAddress.getLocalHost(), 8888);//3. 將數(shù)據(jù)包發(fā)送出去datagramSocket.send(sendPacket);System.out.println("客戶端 向服務(wù)器 : " +InetAddress.getLocalHost() + " : " + 8888 + " 發(fā)送的數(shù)據(jù) : " + string);//4. 退出if("exit".equals(string)){flag = false;}//IV. 接收服務(wù)器反饋的 UDP 數(shù)據(jù)包//1. 接收數(shù)據(jù)包使用的緩沖區(qū)byte[] receiveBuffer = new byte[1024];//2. 接收 UDP 數(shù)據(jù)包使用的 DatagramPacket 對(duì)象DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);//3. 接收 UDP 數(shù)據(jù)包datagramSocket.receive(receivePacket);//4. 獲取發(fā)送端的 IP 地址String sendIP = receivePacket.getAddress().getHostAddress();//5. 獲取發(fā)送端的端口號(hào)int sendPort = receivePacket.getPort();//6. 獲取接收到的數(shù)據(jù)的長(zhǎng)度int receiveLen = receivePacket.getLength();//7. 獲取接收到的數(shù)據(jù) , 并轉(zhuǎn)為字符串String receiveData = new String(receivePacket.getData(), 0, receiveLen);//8. 打印接收到的數(shù)據(jù)包信息System.out.println("客戶端 接收到服務(wù)器端反饋信息 : " +sendIP + " : " + sendPort + " 發(fā)送的數(shù)據(jù) : " + receiveData);}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {System.out.println("客戶端 運(yùn)行結(jié)束");}}}
IV 服務(wù)器 客戶端 運(yùn)行結(jié)果
先運(yùn)行服務(wù)器端 , 再運(yùn)行客戶端 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 网络编程】UDP 服务器 与 客户端持续交互 案例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Java 网络编程】UDP 服务器 客
- 下一篇: 【Java 网络编程】TCP 简介