目錄
?編輯
局域網與廣域網?
IP地址和端口號?
實現簡單的服務器客戶端交互
簡單理解socket?
TCP和UDP的差別(初識)
socket面對udp?
DatagramSocket API
DatagramSocket 構造方法
DatagramSocket 方法:
DatagramPacket API?
DatagramPacket 構造方法:
DatagramPacket 方法:
實現回顯服務器和客戶端
網絡協議?
局域網與廣域網?
隨著時代的發展,越來越需要計算機之間互相通信,共享軟件和數據,即以多個計算機協同工作來完成業務,就有了網絡互連。
網絡互連:將多臺計算機連接在一起,完成數據共享。
數據共享本質是網絡數據傳輸,即計算機之間通過網絡來傳輸數據,也稱為網絡通信。
根據網絡互連的規模不同,可以劃分為局域網和廣域網
?局域網是本地,局部組建的一種私有網絡
局域網內的主機之間能方便的進行網絡通信,又稱為內網;局域網和局域網之間在沒有連接的情況下,是無法通信的。
其能通過路由器去使幾臺電腦去連接在一塊,但數量是有限的。
一般家用路由器,常見的是5 個網口:1WAN + 4LAN
要想讓這幾個電腦能夠在同一個局域網中上網,就需要把他們連接到LAN 口,WAN 口是用來連上級的路由器的。
那么能不能讓一個路由器連接的電腦更多呢?
有個叫交換機的東西: 可以擴展路由器的端口,我們把路由器的LAN口連在交換機上,交換機上有一定數量的LAN口從而可以連一定數量的電腦,這樣就可以擴展電腦的數量。
除此之外還有上級路由器連多個下級路由器,從而更多電腦連接在一塊。
那么如果我們在上述設備層層連接之下,就可以構成更復雜的網絡結構了,把更多更多的局域網連接到一起,構成的網絡更加龐大,可能已經覆蓋了一個城市,一個國家,就叫廣域網。
對于廣域網和局域網的定義沒有準確的數量要求。(我們感覺非常多的電腦(10w臺這種)連接在一塊就是可以稱為廣域網)
IP地址和端口號?
IP地址描述了一個設備,在網絡上的地址,
生活中: 吉林省長春市東北師范大學光華xxx
而在計算機中: 使用一個 32 位, 4 字節數字, 表示地址
一般來說,我們會把 IP 地址給表示成 4 個 0-255 之間的十進制數字,并且使用 3個點進行分隔.點分十進制(192.168.2.100)
在網絡通信中,IP地址用于標識主機網絡地址,端口號可以標識主機中發送數據、接收數據的程序。簡單說:端口號用于定位主機中的程序。
類似發送快遞時,不光需要指定收貨地址(IP地址),還需要指定收貨人(端口號)
格式為:
端口號是0~65535范圍的數字(兩個字節),在網絡通信中,程序可以通過綁定一個端口號,來發送及接收網絡數據注意事項:
兩個不同的程序,不能綁定同一個端口號,但一個進程可以綁定多個端口號
舉個例子:mysql可以綁定一個端口號3306,也可以在綁定其他的端口號,但是其他程序不行綁定3306了。
特殊說明: ? ? ? ? ? ? ??
1-1023 (0不用作端口號)這個范圍的端口號,系統留作特殊用途,咱們寫的程序不應該占用
知名端口號,這些留給一些比較常見的服務器程序進行使用的(都是系統必要的)
22 => ssh
80 => http
443 => https
23 => telnet?
實現簡單的服務器客戶端交互
簡單理解socket?
?之前提過在網絡編程中,應用層到運輸層需要顯式調用 API,而運輸層到網絡層以及后續層的通信通常是自動處理的,不需要開發者主動調用 API,反過來也是同理。
這里顯示調用的API就是socket(套接字)?,只有調用了它,數據才能運輸成功。?
由于傳輸層提供了兩個最核心的協議:UDP?TCP。
因此,socket api 中也提供了兩種風格來面對UDP和TCP。(傳輸層用哪種協議就用哪種風格去應對)
對于socket 不僅是個API,本質上是一種特殊的文件.Socket 就屬于是把"網卡"這個設備,給抽象成了文件了往 socket 文件中寫數據,就相當于通過網卡發送數據.從 socket 文件讀數據,就相當于通過網卡接受數據?
TCP和UDP的差別(初識)
TCP的特點:
有連接
可靠傳輸
面向字節流
全雙工UDP的特點:
無連接
不可靠傳輸
面向數據報
全雙工
連接:
此處說的"連接"不是物理意義的連接,而是抽象,虛擬的連接。
計算機中,這種 抽象 的連接是很常見的,此處的連接本質上就是建立連接的雙方,各自保存對方的信息,兩臺計算機建立連接,就是雙方彼此保存了對方的關鍵信息(ip和端口)
所以這也意味著如果協議是tcp的話,必須要先建立好連接才能傳輸信息,如果是udp,就不用建立連接就能傳輸消息。
可靠傳輸/ 不可靠傳輸:
網絡上存在的"異常情況"是非常多的,無論使用什么樣的軟硬件的技術手段無法100%保證網絡數據能夠從A一定傳輸到。此處談到的"可靠傳輸",盡可能的完成數據傳輸。雖然無法確保數據到達對方,至少可以知道,當前這個數據對方是不是收到了。
此處談到的可靠傳輸,主要指的是發的數據到沒到,發送方能夠清楚的感知到。
面向字節流/面向數據報
面向字節流:此處談到的字節流和文件中的字節流完全一致—— TCP(網絡中傳輸數據的基本單位就是字節)
面向數據報:udp每次傳輸的基本單位是一個數據報(由一系列的字節構成的),它是特定的結構
全雙工/半雙工:
全雙工通信允許數據同時在兩個方向上傳輸。這意味著通信雙方可以同時發送和接收數據,而不會互相干擾。
半雙工通信允許數據在兩個方向上傳輸,但不能同時進行。通信雙方只能交替地發送和接收數據。
socket面對udp?
udp時的socket相較于tcp,要相對簡單,我們先講這個
DatagramSocket API
DatagramSocket 是UDP時的Socket,用于發送和接收UDP數據報。?
DatagramSocket 構造方法
DatagramSocket 方法:
DatagramPacket API?
?DatagramPacket是UDP Socket發送和接收的數據報(UDP面向數據報,每次發送接收數據的基本單位,就是一個UDP數據報)
DatagramPacket 構造方法:
由于udp是沒建立連接的,所以每次發送都要標明要發送的對方ip和端口。(如果建立了連接就不需要發送ip和端口)
DatagramPacket 方法:
構造UDP發送的數據報時,需要傳入 SocketAddress ,該對象可以使用 InetSocketAddress 來創建。
實現回顯服務器和客戶端
注:這里編寫的客戶端服務器是一個簡單 UDP 版本的服務器,稱之為:回顯服務器。
一個普通的服務器:?收到請求,根據請求計算響應(業務邏輯),返回響應。
回顯服務器:?省略了普通服務器的 “根據請求計算響應”(這里的響應一般非常復雜),這里只是為了演示 socket api 的用法。
?這里有一個重點要說下:
對于一個服務器來講,我們需要讓其綁定一個明確的端口號,因為在服務器在網絡傳輸中處于一個被動的狀態,沒有一個明確的端口號,客戶端就無法尋找到請求的服務器。
而對于一個客戶端來說,我們可以讓其隨機分配一個端口號給他,不要指定,因為客戶端是客戶使用,不像我們程序員知道怎么分配端口,客戶不清楚怎么分配端口,萬一客戶指定的端口被別人占用就會報錯,它還不知道怎么修改,所以采用隨機分配。(隨機分配的都是沒被占用的端口號)
以后的服務器客戶端 端口號都遵循這規定
服務器端的邏輯如下:
1. 創建套接字:創建一個 DatagramSocket 對象,并綁定到指定的端口(10003),用于接收和發送數據報。
2. 接收數據報:在 while (true) 循環中,創建一個 DatagramPacket 對象,用于接收客戶端發送的數據報。調用 datagramSocket.receive(datagramPacket) 方法等待并接收數據報。
3. 處理數據:將接收到的數據報中的字節數組轉換為字符串,然后調用 process 方法處理該字符串。在這個例子中,process 方法只是簡單地返回傳入的字符串本身。
4. 發送響應:將處理后的字符串轉換為字節數組,并創建一個新的 DatagramPacket 對象,包含要發送的數據、目標地址和端口(即客戶端的地址和端口)。使用 datagramSocket.send(datagramPacket1) 方法將響應數據報發送回客戶端。
5. 循環處理:上述步驟在 while (true) 循環中不斷重復,服務器持續等待接收新的數據報并響應,直到程序被手動終止。
客戶端設計邏輯:
創建套接字:創建一個 DatagramSocket 對象,用于發送和接收數據報。這個套接字沒有綁定到特定的端口,因此會使用一個臨時端口。
讀取用戶輸入:使用 Scanner 從控制臺讀取用戶輸入的字符串。
發送數據報:
將用戶輸入的字符串轉換為字節數組。
創建一個 DatagramPacket 對象,包含要發送的數據、目標地址和端口。
使用 DatagramSocket 發送數據報。
接收響應:
創建一個 DatagramPacket 對象,用于接收服務器的響應。
使用 DatagramSocket 接收數據報。
將接收到的字節數組轉換為字符串并打印到控制臺。
循環處理:上述步驟在 while (true) 循環中不斷重復,直到程序被手動終止。
public class Serve {public static void main(String[] args) throws IOException,InterruptedException {System.out.println("服務器上線");DatagramSocket datagramSocket=new DatagramSocket(10003);while(true){DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);datagramSocket.receive(datagramPacket);String string=new String(datagramPacket.getData(),0,datagramPacket.getLength());byte[] bytes1=process(string.getBytes());DatagramPacket datagramPacket1 = new DatagramPacket(bytes1,bytes1.length,new InetSocketAddress(datagramPacket.getAddress(),datagramPacket.getPort()));datagramSocket.send(datagramPacket1);}}public static String process(String string){return string;}
}
public class Client {public static void main(String[] args) throws IOException {System.out.println("客戶端啟動");Scanner scanner=new Scanner(System.in);DatagramSocket datagramSocket=new DatagramSocket();while(true){String string=scanner.next();byte[] bytes=string.getBytes();DatagramPacket datagramPacket1 = new DatagramPacket(bytes,bytes.length,new InetSocketAddress("192.168.50.173",10003));datagramSocket.send(datagramPacket1);DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);datagramSocket.receive(datagramPacket);String string1=new String(datagramPacket.getData(),0,datagramPacket.getLength());System.out.println(string1);}}
}
對于這里我們要特殊說幾個點:
1.對于字節數組內部存儲數據報并不可能是全部都占用了,肯定有空閑空間,所以在將該字節數組變為字符串時我們肯定要把空閑空間給劃掉,這時候就用datagrampacket.getlength?()得到有效長度,從而就可以忽略掉,否則會引發bug
2.仔細觀察代碼,發現該服務器可以同時支持多個客戶端
這里有個疑問,一段代碼為什么會能實現多個窗口呢?一般不是只能一段代碼實現一個?這玩意我們是可以修改的
通過這樣修改,我們就能一段代碼生成多個實例對象,多個窗口(客戶端)。
3.對于該DatagramSocket雖然是文件,但是并不需要close,因為Datagramsocket是全程跟隨該進程的,當進程結束時,我們才不會用DatagramSocket,進程只要還在運行,它依然還會用。該進程結束時文件描述表自然就銷毀了,根本不用再添一個close。
網絡協議?
網絡協議是網路通信中的規則和標準,它用于定義網絡通信中數據的傳輸方式、數據包的結構、數據包中的信息內容以及通信雙方的行為等。只有統一規范好了網絡協議(規則),電腦們之間才能通信成功。
本節課的內容就到這里了,剩下的等我下節再講