? ? ? ?回顯服務器表示客戶端發的是啥,服務器就返回啥,主要是為了熟悉UDP數據報網絡編程的基本步驟
????????對于程序的所有分析都寫到了代碼上
UDP回顯服務器代碼
package UdpEcho;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2023-08-09* Time: 11:52*/
//UDP回顯服務器,客戶端發的是啥,服務器就返回啥
//通過UDP回顯服務器的實現來簡單熟悉創建服務器的API
//我們創建了DatagramSocket類的對象,但是在程序中沒有調用close方法關閉該對象
//1.我們整個程序只實例化了一個DatagramSocket類的對象(socket)
//2.socket對象的生命周期非常長,是跟隨整個程序的,此時就需要socket對象保持打開的狀態
//3.socket對象->系統中的socket文件->文件描述符(進程的pcb(進程控制塊)的屬性),最主要的目標是為了釋放文件描述符表中的文件描述符,才要關閉socket對象
//而進程結束,就把pcb回收,里面的文件描述符表自然也被銷毀了
//當程序中有多個socket對象,socket對象的生命周期較短,需要頻繁的創建和釋放,一定要記得close
public class UdpEchoServer {//對于實現UDP服務器DatagramSocket是不可或缺的類//要通過DatagramSocket類的對象(網卡對象)來進行客戶端與服務器之間的數據交換private DatagramSocket socket=null;//在實例化UDP回顯服務器的時候就要實例化一個DatagramSocket對象(網卡對象)//對于服務器我們在實例化DatagramSocket對象時需要指明服務器的端口號,方便客戶端尋找public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);}//定義一個start方法來啟動UDP回顯服務器public void start() throws IOException {System.out.println("服務器啟動");//服務器啟動以后要一直去接收客戶端傳來的請求,并進行處理以及回應while (true){//服務器在啟動以后要處理的三件核心環節//1.讀取客戶端傳來的請求,并解析(客戶端傳來的請求是一個二進制數組,要根據實際情況解析為字符串或數字等等)//UDP服務器進行發送和接收的數據單位是UDP數據報(DatagramPacket)//DatagramPacket數據報類型有兩個參數,當DatagramPacket類型的對象用于接收數據,就不需要提供ip地址和端口號(SocketAddress)DatagramPacket requestPacket=new DatagramPacket(new byte[4080],4080);//客戶端傳來的請求(數據報)就會存儲到DatagramPacket類型的對象requestPacket中//receive方法自帶阻塞等待,當服務器沒有接受到客戶端傳來的請求時,在receive方法這里就會進入阻塞等待,直到客戶端傳來請求為止socket.receive(requestPacket);//2.根據請求,計算出響應(這個是在實際工作中我們最主要編寫的邏輯)//由于回顯服務器對數據的處理很簡單(客戶端發的是啥,服務器就返回啥)//所以我們將客戶端發出的請求轉換為字符串再把字符串傳遞給客戶端即可String request=new String(requestPacket.getData(),0,requestPacket.getLength());String repose=handle(request);//3.把響應發送給客戶端//發送的響應也是DatagramPacket(UDP數據報)類型//由于要將響應發送給客戶端,所以需要知道客戶端的ip地址和端口號(SocketAddress類型)//requestPacket(接收客戶端傳來的請求)中含有服務器和客戶端的ip地址和端口號//可以通過getSocketAddress方法獲得客戶端的ip地址和端口號(SocketAddress類)DatagramPacket reponsePacket=new DatagramPacket(repose.getBytes(),repose.getBytes().length,requestPacket.getSocketAddress());socket.send(reponsePacket);//服務器就完成了接收數據,處理數據,發送數據的過程//記錄日志,方便觀察程序執行效果//requestPacket是客戶端傳給服務器的請求報,所以其中有客戶端和服務器的ip地址和端口號//通過getAddress方法獲得客戶端的ip地址,getPort方法獲得客戶端的端口號System.out.printf("[%s,%d] request:%s repose:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,repose);}}//對客戶端傳來的請求進行處理private String handle(String request){return request;}public static void main(String[] args) throws IOException {UdpEchoServer udpEchoServer=new UdpEchoServer(8080);udpEchoServer.start();}
}
UDP回顯客戶端的代碼
package UdpEcho;import java.io.IOException;
import java.net.*;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2023-08-09* Time: 11:53*/
//UPD回顯客戶端
public class UdpEchoClient {private DatagramSocket socket=null;private String ipServer=null; //用來存儲用戶提供的服務器ip地址private int portSever=0; //用來存儲用戶提供的服務器端口號//在實例化客戶端的時候需要用戶提供服務器的ip地址和端口號,這樣才知道該客戶端要聯系哪個服務器public UdpEchoClient(String ipServer,int portSever) throws SocketException {this.ipServer=ipServer;this.portSever=portSever;//因為客戶端的端口號是有操作系統隨機分配的,要是指定客戶端的端口號可能會導致沖突//所以實例化DatagramSocket對象的時候不寫參數,不指定端口號socket=new DatagramSocket();}//開啟客戶端public void start() throws IOException {Scanner scanner=new Scanner(System.in);System.out.println("客戶端啟動");//要不停的讀取用戶輸入的請求,將請求發送給服務器,并接收服務器發送回來的響應while (true){System.out.print("請求->");String request=scanner.next();//根據用戶輸入的請求實例化DatagramPacket數據報(因為UDP類型網絡編程數據傳輸的基本單位是DatagramPacket數據報)//由于要將客戶端的請求發送給服務器,所以需要在DatagramPacket類中聲明服務器的ip地址和端口號//通過InetAddress類調用靜態方法getByName實例化InetAddress類型的對象,getByName方法可以叫做工廠方法DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(ipServer),portSever);//將用戶的請求發送給客戶端socket.send(requestPacket);//接收服務器返回的的回應DatagramPacket reposePacket=new DatagramPacket(new byte[4080],4080);socket.receive(reposePacket);//對回應的數據報進行解析String repose=new String(reposePacket.getData(),0,reposePacket.getLength());//輸出解析后得到的回應System.out.println(repose);}}public static void main(String[] args) throws IOException {UdpEchoClient udpEchoClient=new UdpEchoClient("127.0.0.1",8080);udpEchoClient.start();}
}
當我們用idea實現了上面的代碼后可以通過idea如何開啟多個客戶端(一個代碼開啟多個客戶端運行)來檢驗多個客戶端向服務器傳送請求的運行情況