【Java 网络编程】UDP 服务器 客户端 通信 ( DatagramSocket | DatagramPacket | UDP 发送数据包 | UDP 接收数据包 | 端口号分配使用机制 )
文章目錄
- I UDP 信息發(fā)送接收原理
- II UDP 發(fā)送和接收端口相同
- III UDP 發(fā)送信息代碼示例
- IV UDP 接收信息代碼示例
- V UDP 服務(wù)器端代碼示例
- VI UDP 客戶端代碼示例
- VII 客戶端服務(wù)器端通信
I UDP 信息發(fā)送接收原理
1. UDP 既有客戶端的功能 , 也有服務(wù)器端的功能 ;
2. UDP 發(fā)送和接收 : 計算機(jī) A 向 計算機(jī) B 的 X 端口發(fā)送消息 , B 不一定能接收到 , B 能收到并處理該消息的前提是 , B 當(dāng)前正在監(jiān)聽 X 端口 ;
3. 發(fā)送設(shè)備個數(shù) : B 監(jiān)聽 X 端口 , 并接收數(shù)據(jù) , 向 B 發(fā)送信息的設(shè)備可以是多個 , B 可以接收到任何設(shè)備向其 X 端口發(fā)送的數(shù)據(jù) ;
4. 端口號說明 : UDP 報文頭 64 位 , 其中有發(fā)送源端口號 , 和接收的目標(biāo)端口號 , 這個目標(biāo)端口號是 X 端口號 , 發(fā)送源端口號是隨機(jī)的動態(tài)端口號 ;
5. 相互通信 : B 收到消息時 , 才知道 A 設(shè)備發(fā)送消息的端口號 ; 如果 B 收到消息 , 然后馬上向 A 的發(fā)送源端口號回送一條消息 , 如果 A 計算機(jī)正在監(jiān)聽這個端口號 , 就可以收到 B 計算機(jī)發(fā)送的消息 ; 如果 A 沒有監(jiān)聽 , 那么收不到這個消息 ;
II UDP 發(fā)送和接收端口相同
UDP 發(fā)送和接收使用的是同一個端口 ;
UDP 發(fā)送和接收使用的是同一個端口 ;
UDP 發(fā)送和接收使用的是同一個端口 ;
重要的事情說三遍
III UDP 發(fā)送信息代碼示例
1. 創(chuàng)建 DatagramSocket 對象 : 發(fā)送 UDP 數(shù)據(jù)包 , 首先要創(chuàng)建 DatagramSocket 對象 , 該對象可用于 UDP 數(shù)據(jù)包的發(fā)送和接收 , 創(chuàng)建時如果需要監(jiān)聽數(shù)據(jù)的接收 , 可以指定監(jiān)聽的端口 , 也可以等待系統(tǒng)自動分配一個端口 , 使用該端口進(jìn)行數(shù)據(jù)的發(fā)送和接收 ;
2. 創(chuàng)建并設(shè)置 DatagramPacket 對象 : 發(fā)送的數(shù)據(jù)包實體是 DatagramPacket 對象 , 將目標(biāo)設(shè)備的 IP 地址 , 端口號 , 發(fā)送的 byte[] 數(shù)組數(shù)據(jù) , 設(shè)置到該數(shù)據(jù)包實體中 , 調(diào)用 DatagramSocket 對象的 send 方法 , 將該數(shù)據(jù)包發(fā)送出去 ;
3. 動態(tài)端口號自動分配 : 這里注意 , 發(fā)送的同時 , 系統(tǒng)自動分配了 一個動態(tài)端口號 , 該發(fā)送端口號就是接受端口號 , UDP 開始監(jiān)聽該端口號 , 意味著可以從該端口號接受數(shù)據(jù)包 , 服務(wù)器端就是接收到信息后 , 將反饋數(shù)據(jù)發(fā)送到該動態(tài)分配的端口中 ;
//I. 創(chuàng)建 DatagramSocket 對象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包套接字 , 客戶端 ,// 無需指定端口 , 讓系統(tǒng)直接分配一個端口 , 使用該端口發(fā)送和接收數(shù)據(jù)DatagramSocket datagramSocket = new DatagramSocket();//II. 發(fā)送 UDP 數(shù)據(jù)包//2. 客戶端發(fā)送給服務(wù)器端的端口號String sendMessage = "你好, 服務(wù)器 !";//3. 將字符串轉(zhuǎn)為 byte[] 數(shù)組byte[] sendData = sendMessage.getBytes();//4. 創(chuàng)建發(fā)送數(shù)據(jù)包 , 需要傳入的參數(shù) 1> 數(shù)據(jù) 2> 數(shù)據(jù)長度 3> 接收者的地址 4> 接收者的端口號// 向服務(wù)器端發(fā)送數(shù)據(jù) , 發(fā)送的端口是自動分配的DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,InetAddress.getLocalHost(), 8888);//5. 將數(shù)據(jù)包發(fā)送出去datagramSocket.send(sendPacket);IV UDP 接收信息代碼示例
1. 創(chuàng)建 DatagramSocket 對象 : 接收 UDP 數(shù)據(jù)包 , 首先要創(chuàng)建 DatagramSocket 對象 , 注意必須設(shè)置一個監(jiān)聽的端口號 , 才能接收數(shù)據(jù)包 ;
客戶端沒有設(shè)置監(jiān)聽端口號 , 接收到了數(shù)據(jù) , 是因為其先發(fā)送的數(shù)據(jù) , 發(fā)送數(shù)據(jù)的同時 , 系統(tǒng)自動為其分配了一個動態(tài)端口號 , UDP 中發(fā)送和接收使用的是同一個端口號 , 在分配完該動態(tài)端口號之后 , 客戶端就開始監(jiān)聽該端口號了 ;
2. 創(chuàng)建并設(shè)置 DatagramPacket 對象 : 接收的數(shù)據(jù)包實體是 DatagramPacket 對象 , 需要為其設(shè)置一個接收數(shù)據(jù)的緩沖區(qū) , 接收到數(shù)據(jù)包后 , 系統(tǒng)會自動將發(fā)送信息的設(shè)備的 IP 地址 , 端口號 , 發(fā)送的 byte[] 數(shù)組數(shù)據(jù) , 設(shè)置到該數(shù)據(jù)包實體中 , 調(diào)用 DatagramSocket 對象的 receive 方法 , 會阻塞等待數(shù)據(jù)包到來 ;
//I. 創(chuàng)建 DatagramSocket 對象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包接收者 , 監(jiān)聽 8888 端口// 該 DatagramSocket 既可以接收數(shù)據(jù)包 , 也可以發(fā)送數(shù)據(jù)包DatagramSocket datagramSocket = new DatagramSocket(8888);//II. 接收 UDP 數(shù)據(jù)包//2. 接收數(shù)據(jù)包使用的緩沖區(qū)byte[] receiveBuffer = new byte[1024];//3. 接收 UDP 數(shù)據(jù)包使用的 DatagramPacket 對象DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);//4. 接收 UDP 數(shù)據(jù)包datagramSocket.receive(receivePacket);V UDP 服務(wù)器端代碼示例
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;public class UDPServer {public static void main(String[] args){try {System.out.println("服務(wù)器 開始運(yùn)行");//I. 創(chuàng)建 DatagramSocket 對象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包接收者 , 監(jiān)聽 8888 端口// 該 DatagramSocket 既可以接收數(shù)據(jù)包 , 也可以發(fā)送數(shù)據(jù)包DatagramSocket datagramSocket = new DatagramSocket(8888);//II. 接收 UDP 數(shù)據(jù)包//2. 接收數(shù)據(jù)包使用的緩沖區(qū)byte[] receiveBuffer = new byte[1024];//3. 接收 UDP 數(shù)據(jù)包使用的 DatagramPacket 對象DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);//4. 接收 UDP 數(shù)據(jù)包datagramSocket.receive(receivePacket);//5. 獲取發(fā)送端的 IP 地址String sendIP = receivePacket.getAddress().getHostAddress();//6. 獲取發(fā)送端的端口號int sendPort = receivePacket.getPort();//7. 獲取接收到的數(shù)據(jù)的長度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);//III. 發(fā)送 UDP 數(shù)據(jù)包//10. 將接收到的數(shù)據(jù)長度回送給發(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ù)長度 3> 接收者的地址 4> 接收者的端口號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);} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {System.out.println("服務(wù)器 運(yùn)行結(jié)束");}}}
VI UDP 客戶端代碼示例
import java.io.IOException; 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("客戶端 開始運(yùn)行");//I. 創(chuàng)建 DatagramSocket 對象 , 用于 UDP 數(shù)據(jù)包的發(fā)送和接收//1. UDP 數(shù)據(jù)包套接字 , 客戶端 ,// 無需指定端口 , 讓系統(tǒng)直接分配一個端口 , 使用該端口發(fā)送數(shù)據(jù)DatagramSocket datagramSocket = new DatagramSocket();//II. 發(fā)送 UDP 數(shù)據(jù)包//2. 客戶端發(fā)送給服務(wù)器端的端口號String sendMessage = "你好, 服務(wù)器 !";//3. 將字符串轉(zhuǎn)為 byte[] 數(shù)組byte[] sendData = sendMessage.getBytes();//4. 創(chuàng)建發(fā)送數(shù)據(jù)包 , 需要傳入的參數(shù) 1> 數(shù)據(jù) 2> 數(shù)據(jù)長度 3> 接收者的地址 4> 接收者的端口號// 向服務(wù)器端發(fā)送數(shù)據(jù) , 發(fā)送的端口是自動分配的DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,InetAddress.getLocalHost(), 8888);//5. 將數(shù)據(jù)包發(fā)送出去datagramSocket.send(sendPacket);System.out.println("客戶端 向服務(wù)器 : " +InetAddress.getLocalHost() + " : " + 8888 + " 發(fā)送的數(shù)據(jù) : " + sendMessage);//III. 接收 UDP 數(shù)據(jù)包//6. 接收數(shù)據(jù)包使用的緩沖區(qū)byte[] receiveBuffer = new byte[1024];//7. 接收 UDP 數(shù)據(jù)包使用的 DatagramPacket 對象DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);//8. 接收 UDP 數(shù)據(jù)包datagramSocket.receive(receivePacket);//9. 獲取發(fā)送端的 IP 地址String sendIP = receivePacket.getAddress().getHostAddress();//10. 獲取發(fā)送端的端口號int sendPort = receivePacket.getPort();//11. 獲取接收到的數(shù)據(jù)的長度int receiveLen = receivePacket.getLength();//12. 獲取接收到的數(shù)據(jù) , 并轉(zhuǎn)為字符串String receiveData = new String(receivePacket.getData(), 0, receiveLen);//13. 打印接收到的數(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é)束");}}}
VII 客戶端服務(wù)器端通信
1. 服務(wù)器運(yùn)行 : 先運(yùn)行服務(wù)器 , 此時服務(wù)器開始監(jiān)聽 8888 端口 ,
2. 客戶端發(fā)送信息 : 再運(yùn)行客戶端 , 客戶端向服務(wù)器端的 8888 端口發(fā)送數(shù)據(jù) , 客戶端的發(fā)送端口是隨機(jī)的 , 本次是 57660 端口 , 這是個動態(tài)分配端口 , UDP 的發(fā)送和接收端口是同一個端口 , 此時 UDP 開始監(jiān)聽該端口 ;
3. 服務(wù)器端反饋信息 : 服務(wù)器端收到客戶端發(fā)送的數(shù)據(jù) , 處理后將反饋數(shù)據(jù)再次發(fā)送回去 , 這里發(fā)送給客戶端的 57660 端口 , 服務(wù)器端的發(fā)送端口就是 8888 端口 ;
UDP 發(fā)送和接收端口是同一個端口 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 网络编程】UDP 服务器 客户端 通信 ( DatagramSocket | DatagramPacket | UDP 发送数据包 | UDP 接收数据包 | 端口号分配使用机制 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 网络编程】UDP API 简
- 下一篇: 【Java 网络编程】UDP 服务器 与