目錄
網絡通信基礎
UDP通信
服務器
1.想要使用UDP通信 要先打開DatagramSocket文件 端口號可以手動指定或系統隨機分配
2.阻塞等待接收客戶端數據;創建DatagramPacket接收客戶端傳來的數據
3.處理客戶端傳來的數據,并進行業務處理(這里只演示UDP通信 所以只是回傳數據)
4.處理數據成DatagramPacket并發送數據給客戶端
整體代碼
客戶端
1.創建DatagramSocket (這里客戶端端口號系統分配即可,不允許和服務器同一端口號)
2.客戶端接收用戶的數據
3.處理用戶數據成DatagramPacket 指定要發送服務器的地址與端口號
4.發送數據給客戶端
5.阻塞等待服務器響應
6.處理服務器響應的數據
7.顯示數據給用戶
整體代碼
繼承服務器代碼,重寫業務代碼即可
網絡通信基礎
- 物理層:網絡通信的基礎設施? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 運快遞的公路
- 數據鏈路層:兩個相鄰的節點之間如何傳輸? ? ? ? ? ? ? ?兩個集散點之間的傳輸
- 網絡層:兩個點之間的路徑規劃? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?物流公司規劃快遞的路徑
- 傳輸層:兩個點之間的通信(不考慮路徑規劃)? ? ? ? 賣家發貨 只考慮起點和終點
- 應用層:數據傳輸過去之后 如何使用? ? ? ? ? ? ? ? ? ? ? ? ?快遞拿到之后如何使用
網絡編程的主要工作寫應用層的代碼,處理應用層的協議數據
從5->1往下傳輸 每次傳輸都會依次添加報頭 稱為封裝? ? QQ1發送
從1->5往上傳輸 每次傳輸都會解析去掉報頭? ? ? ? ? ? ? ? ? ?QQ2接收
傳輸層提供兩種協議
TCP:有連接,可靠傳輸,面向字節流,全雙工
UDP:無連接,不可靠傳輸,面向數據包,半雙工
可靠傳輸:數據對方有沒有接收到,發送方有感知;打電話就是可靠的,可以知道對方有沒有聽到。
不可靠傳輸:數據對方有沒有接收到,不管,也不知道;微信就是不可靠,不知道對方有沒有看到我的消息。
全雙工:雙向通信 可以A->B B->A 同時進行
半雙工:單向通信 A->B或者B->A 同時只允許一個進行
程序要進行網絡通信,需要一個端口號(客戶端與服務器的端口號不能相同!)
端口號相當于用來在網絡上區分進行的身份標識符
分配端口號有 1.手動指定 2.系統自動分配
UDP通信
UDP的Socket API
DatagramSocket和DatagramPaclet 核心類
socket類本質相當于文件 構造一個DatagramSock對象,相當于打開了一個內核中的socket文件
打開后就可以傳輸數據了
傳輸數據已 DatagramPacket為基本單位
InetSocketAddress類 IP地址+端口號
send發送數據 receive接收數據 close關閉數據
DatagramOacket 表示一個UDP數據報 UDP是面向數據報的協議
服務器
1.想要使用UDP通信 要先打開DatagramSocket文件 端口號可以手動指定或系統隨機分配
//想要使用UDP服務器 要打開一個文件private DatagramSocket socket=null;//創建對象//服務器IP和端口號是提供給客戶端 方便客戶端知道地址發送過來public Test1(int port) throws SocketException {socket=new DatagramSocket(port);//創建實例 綁定進程端口號
2.阻塞等待接收客戶端數據;創建DatagramPacket接收客戶端傳來的數據
DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);//客戶端發來的請求放到參數datagramPacket 輸出性參數System.out.println("我正在等待!");socket.receive(datagramPacket);//阻塞等待 客戶端發起請求System.out.println("服務器接收到數據");
3.處理客戶端傳來的數據,并進行業務處理(這里只演示UDP通信 所以只是回傳數據)
//把傳來的數據構造成數據 1.獲取數據 從0開始構造 構造到數據結尾String request=new String(datagramPacket.getData(),0,datagramPacket.getLength());System.out.println("接收到的數據:"+request);//處理業務String requst=process(request);System.out.println("服務器處理數據");public String process(String s){return s;}
4.處理數據成DatagramPacket并發送數據給客戶端
//要傳回客戶端也要把數據構造成DatagramPacket//把string構造到byte字節 1.字節數據,2.字節長度 3.客戶端的id+客戶端的端口號DatagramPacket datagramPackets=new DatagramPacket(request.getBytes(),request.getBytes().length,datagramPacket.getSocketAddress());//發送數據socket.send(datagramPackets);System.out.println("服務器發送數據成功");System.out.printf("[地址:%s:端口號:%d] 發來數據:%s 服務器響應數據:%s\n",datagramPacket.getAddress().toString(),datagramPacket.getPort(),request,requst);
整體代碼
package DemoUDP;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;//服務端
public class Test1 {//想要使用UDP服務器 要打開一個文件private DatagramSocket socket=null;//創建對象//服務器IP和端口號是提供給客戶端 方便客戶端知道地址發送過來public Test1(int port) throws SocketException {socket=new DatagramSocket(port);//創建實例 綁定進程端口號}public void start() throws IOException {System.out.println("啟動服務器");while (true){//創建一個DatagramPacket(創建緩存區,緩存區長度)用來接收客戶端發來的請求DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);//客戶端發來的請求放到參數datagramPacket 輸出性參數System.out.println("我正在等待!");socket.receive(datagramPacket);//阻塞等待 客戶端發起請求System.out.println("服務器接收到數據");//把傳來的數據構造成數據 1.獲取數據 從0開始構造 構造到數據結尾String request=new String(datagramPacket.getData(),0,datagramPacket.getLength());System.out.println("接收到的數據:"+request);//處理業務String requst=process(request);System.out.println("服務器處理數據");//要傳回客戶端也要把數據構造成DatagramPacket//把string構造到byte字節 1.字節數據,2.字節長度 3.客戶端的id+客戶端的端口號DatagramPacket datagramPackets=new DatagramPacket(request.getBytes(),request.getBytes().length,datagramPacket.getSocketAddress());//發送數據socket.send(datagramPackets);System.out.println("服務器發送數據成功");System.out.printf("[地址:%s:端口號:%d] 發來數據:%s 服務器響應數據:%s\n",datagramPacket.getAddress().toString(),datagramPacket.getPort(),request,requst);}}public String process(String s){return s;}public static void main(String[] args) throws IOException {//端口號范圍 0--65535 1024以下的端口是系統用的 盡量用1024以上 65535以下Test1 test1=new Test1(8080);test1.start();}
}
客戶端
1.創建DatagramSocket (這里客戶端端口號系統分配即可,不允許和服務器同一端口號)
DatagramSocket Socket=null;//客戶端端口號需要系統自動分配 不能指定與服務器端口號一樣,不然會搶占服務器端口號 導致后啟動的一端無法啟動public Test2() throws SocketException {Socket=new DatagramSocket();}
2.客戶端接收用戶的數據
Scanner scanner=new Scanner(System.in);System.out.println("客戶端輸入數據:>");String Data=scanner.nextLine();
3.處理用戶數據成DatagramPacket 指定要發送服務器的地址與端口號
//處理用戶數據//1.把string類型處理成byte字節數據 datagramPacket類型 里面附帶發送地址和發送對方的端口號DatagramPacket datagramPacket=new DatagramPacket(Data.getBytes(),Data.getBytes().length, InetAddress.getByName("127.0.0.1"),8080);System.out.println("客戶端處理數據");
4.發送數據給客戶端
//發送數據Socket.send(datagramPacket);System.out.println("客戶端發送數據");
5.阻塞等待服務器響應
//阻塞等待服務器的響應數據DatagramPacket datagramPackets=new DatagramPacket(new byte[1024],1024);Socket.receive(datagramPackets);System.out.println("客戶端接收服務器響應數據");
6.處理服務器響應的數據
//處理服務器響應的數據String Datas=new String(datagramPackets.getData(),0,datagramPackets.getLength());System.out.println("客戶端處理數據");
7.顯示數據給用戶
System.out.printf("服務器響應數據:%s\n",Datas);
整體代碼
package DemoUDP;import java.io.IOException;
import java.net.*;
import java.util.Scanner;//客戶端
public class Test2 {DatagramSocket Socket=null;//客戶端端口號需要系統自動分配 不能指定與服務器端口號一樣,不然會搶占服務器端口號 導致后啟動的一端無法啟動public Test2() throws SocketException {Socket=new DatagramSocket();}public void start() throws IOException {while (true){//接收用戶數據Scanner scanner=new Scanner(System.in);System.out.println("客戶端輸入數據:>");String Data=scanner.nextLine();//處理用戶數據//1.把string類型處理成byte字節數據 datagramPacket類型 里面附帶發送地址和發送對方的端口號DatagramPacket datagramPacket=new DatagramPacket(Data.getBytes(),Data.getBytes().length, InetAddress.getByName("127.0.0.1"),8080);System.out.println("客戶端處理數據");//發送數據Socket.send(datagramPacket);System.out.println("客戶端發送數據");//阻塞等待服務器的響應數據DatagramPacket datagramPackets=new DatagramPacket(new byte[1024],1024);Socket.receive(datagramPackets);System.out.println("客戶端接收服務器響應數據");//處理服務器響應的數據String Datas=new String(datagramPackets.getData(),0,datagramPackets.getLength());System.out.println("客戶端處理數據");//顯示處理后的數據給用戶System.out.printf("服務器響應數據:%s\n",Datas);}}public static void main(String[] args) throws IOException {Test2 test2=new Test2();test2.start();}
}
繼承服務器代碼,重寫業務代碼即可
package DemoUDP;import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;public class Test3 extends Test1{public Test3(int port) throws SocketException {super(port);}@Overridepublic String process(String s) {Map<String,String> dic=new HashMap<String,String>();dic.put("cat","貓");return dic.getOrDefault(s,"此單詞還未更新");}public static void main(String[] args) throws IOException {Test3 test3=new Test3(8080);test3.start();}}
指定客戶端多開
之后就可以同時運行多個客戶端訪問服務器