網路基礎
前言
對於開發人員來說,網路部分一直是一個不痛不癢的基礎內容。但是作為開發人員,對一些常見的通訊協議還是需要學習和了解的,只是不用像網路專業人士那樣學的很深入,作為分散式基礎的一部分,這裡也對網路知識做出一個簡單的總結。
網路分層模型
這個其實是大學計算機網路基礎課(奈何這門課概念巨多,長期沒接觸,大部分都遺忘了)。目前的網路分層模型主要是兩個,OSI七層參考模型和TCP/IP四層模型,但是OSI分層模型並不實用,現在提到的網路分層模型一般都是指的TCP/IP網路模型
這篇部落格中的一些圖片總結的不錯,可以參考:網路分層模型
需要知道TCP/IP網路模型的具體具體指的是:應用層、網路層、傳輸層、資料鏈路層和物理層。
網路協議
針對網路協議,我們需要重點了解IP協議和TCP/UDP協議。
協議:其實簡單點理解就是規定了報文的交換方式和包含的含義,沒什麼特別的
IP協議
IP協議詳細解釋,可以參考下面的部落格,其中針對IP資料包也有介紹,這裡不做詳細討論:IP協議及資料包詳解
IP協議其實是網路層的協議,是為TCP和UDP協議服務的,IP協議寫明瞭目的地址,就像我們寄包裹一樣需要寫明目的地址。但是IP協議只是一個"盡力而為"的協議,在網路傳輸過程中可能會出現報文丟失、報文順序打亂和報文重複傳送的問題。對於報文的準確送達與否,交給了上一層來完成。TCP、UDP這兩層協議就是建立在IP層提供的基礎服務之上。根據應用程式需求的不同,可以選擇可靠的傳輸(TCP)或者不可靠的傳輸(UDP)協議
TCP/UDP協議
TCP協議與UDP協議最大的不同就在於,TCP協議能夠檢測和恢復IP層提供的主機到主機的通訊中可能發生的報文丟失、報文重複及其他錯誤。TCP提供了一個可信賴的位元組流通道。
UPD協議只是簡單的擴充套件了IP協議的“盡力而為”的功能,因此使用UDP報文,在必要的時候需要考慮報文的丟失和順序混亂的問題。
TCP同時是一種面向連線的協議,這是其保證資料不丟失的基本所在,針對TCP建立和斷開連線的過程,就是我們常常談到的三次握手和四次揮手(本科學的巨好,現在忘得一乾二淨,扎心啊),下面會重點針對TCP如何建立和斷開連線進行詳細探討。
三次握手和四次揮手
這個也是一個基礎知識,網上一大堆博文在講這個,但是大多都只是在介紹概念,解釋的不是十分通俗,在參考了很多部落格之後,發現這篇文章還算介紹的比較通俗:三次握手和四次揮手通俗解釋(本文中的一些圖,也是盜用的這篇部落格)
三次握手
其實上面的一個圖就通俗的解釋了三次握手,以及握手為什麼是三次,總的來說,任何一種通訊都沒法保證絕對可靠,只是三次握手是建立可靠連線的基本保證。
這個結合上一個圖理解三次握手,就不難了。
針對三次握手中還有一個SYN攻擊,這個攻擊會造成大量的資料包阻塞,這個問題可以參考這篇博文SYN攻擊(這個只是瞭解瞭解)
四次揮手
在理解了三次握手的基礎上,再理解四次握手,就比較容易了,先上圖
說明:其中的ACK是在收到的報文seq的基礎上+1,
這裡只需要解釋為什麼是四次揮手即可,四次揮手其實就是表示TCP斷開連線的時候,客戶端和服務端均可主動發起揮手動作,為什麼是四次,其根本原因就在於三次握手的時候,Client端(客戶端)可以直接傳送SYN+ACK報文,但是在斷開連線的過程中,服務端(這裡依舊以客戶端主動發起斷開連線為例)收到FIN報文的時候並不會立即關閉通訊管道,因為可能還有訊息沒有處理完,所以只能暫時回覆客戶端一個ACK報文,表示客戶端傳送的斷開連線的報文收到了,等我的資料傳送完成之後我才能傳送FIN報文,於是就有了上面的那張圖。
傳輸過程的流量控制和確認機制
針對傳輸過程中的流量控制和確認,其實核心內容就是關於滑動視窗的,但是這一部分也是理解後面的BIO和NIO的基礎
滑動視窗
這個其實也不是什麼新的概念,在老謝的計算機網路教材中依舊存在,只是早就還給老師了。
滑動視窗協議的主要目的就是解決擁塞問題,避免出現接收方來不及接受的情況。滑動視窗是一種流量控制技術,早期的網路通訊中,通訊雙方不會考慮網路的擁塞情況,同時傳送資料,導致中間節點阻塞或者掉包,會出現誰也傳送不了資料的情況,因此就有了滑動視窗協議來解決這個問題。
滑動視窗的大小在TCP三次握手建立連線的時候就已經確定了。同時另外一點,也是最重要的一點,滑動視窗滑動的依據,就是隻有收到接受方確認的訊息回覆,滑動視窗才會向前移動一個窗格。下圖是滑動視窗的動畫示例圖
Socket
這個其實已經不再陌生,Java中對TCP和UDP通訊做了相應的封裝,其中Socket就是用來互相通訊的物件而已,其使用起來更像是一個流物件,如果還不能對Socket有更好的理解,可以參看這篇部落格Java Socket理解
這裡先來一個簡單的Socket例項,目的是為了引出後面的BIO和NIO
TCP簡單例項
客戶端例項程式碼
package com.learn;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
*/
public class ClientSocketDemo {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("127.0.0.1",8080);
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
out.write("hello ,this is client");
//清空緩衝區中的資料
out.flush();
System.out.println("資料已經傳送");
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Socket服務端程式碼
package com.learn;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
*/
public class ServerSocketDemo {
public static void main(String[] args) {
ServerSocket serverSocket = null;
BufferedReader bufferReader = null;
try {
serverSocket = new ServerSocket(8080);
System.out.println("服務端啟動......");
//服務端會在這裡阻塞,獲取客戶端的資料
Socket socket = serverSocket.accept();
//讀取客戶端的資料
bufferReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//輸出客戶端資料
System.out.println("收到的客戶端資料為:"+bufferReader.readLine());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(bufferReader!=null){
try {
bufferReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket!=null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
執行結果:
UDP簡單例項
直接上例項吧
服務端程式碼
package com.learn.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
*/
public class UDPServer {
public static void main(String[] args) {
//建立服務並且接受一個資料包
try {
DatagramSocket datagramSocket = new DatagramSocket(8089);
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
//socket將接受的資料放到receivePacket中
datagramSocket.receive(receivePacket);
System.out.println("服務端收到的資料為:");
System.out.println(new String(receiveData,0,receivePacket.getLength()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
客戶端程式碼
package com.learn.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
*/
public class UDPClient {
public static void main(String[] args) {
try {
DatagramSocket datagramSocket = new DatagramSocket();
InetAddress address = InetAddress.getByName("localhost");
byte[] sendData = "hello this is client udp".getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,sendData.length,address,8089);
datagramSocket.send(sendPacket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
上面的兩個例項可以說非常熟悉了,其實並不是什麼新的東西,就相當於Socket的helloworld,可以說只要談到Socket上述的兩個例子是必須要拿出來走一遍的。
下面附上一個服務端和客戶端能雙向通訊的例項,為了方便我們更好的理解雙方的資料互動
Client端程式碼:
package com.learn.tcp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
* <p>
* 可以多次傳送資料
*/
public class ClientMultiDemo {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8080);
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
PrintWriter os = new PrintWriter(socket.getOutputStream());
BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = sin.readLine();
while (!"bye".equals(line)) {
os.println(line);
os.flush();
System.out.println("客戶端準備傳送的資訊:" + line);
System.out.println("接收到的服務端資訊:" + is.readLine());
line = sin.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server端程式碼
package com.learn.tcp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by liman on 2018/8/11.
* QQ:657271181
* e-mail:liman65727@sina.com
*
* 可以處理多個客戶端請求的ServerSocket
*/
public class ServerSocketMutilDemo {
public static void main(String[] args) {
ServerSocket server = null;
try {
server = new ServerSocket(8080);
Socket socket = server.accept();
//從客戶端中讀取資訊
BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//用於向客戶端寫資料的輸出流
PrintWriter os = new PrintWriter(socket.getOutputStream());
//這個只是讀取控制檯輸入
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
String line = sin.readLine();
while(!"bye".equals(line)){
os.println(line);
os.flush();
System.out.println("服務端即將傳送的資料:"+line);
System.out.println("收到的客戶端資料為:"+is.readLine());
line = sin.readLine();
}
//這裡為了簡單,直接在這裡關閉流物件
os.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
執行例項:
BIO簡單理解
上述程式碼的執行過程,可以用下圖簡單來表示
其中每次伺服器處理請求的時候,客戶端就只能阻塞,等待伺服器處理相應的請求。如果我們想在上面做點優化,首先想到的就是利用多執行緒或者執行緒池。如下圖所示:
其實這個就是BIO的一個模型了,tomcat之前的版本就是基於BIO的,在7.7以後變成了NIO。
其實最大的問題就是在與基於緩衝區的資料傳送和接受機制,如果緩衝區沒有填滿資料,緩衝區是不可讀的,因此在資料填滿緩衝區之前,客戶端和服務端都是阻塞的,這就非常影響效率了
於是就有了NIO,每一個客戶端在服務端註冊一個channel,然後 服務端直接輪詢這些channel,這個具體後面學習到Netty的時候,再進行補充。
這篇部落格暫時更新到這兒,後續學習netty的時候進行補充。(To Be Continued......未完待續)
相關文章
- 網路基礎概念
- 網路基礎(一)
- 網路基礎總結
- 18作 網路基礎
- 計算機網路基礎計算機網路
- 神經網路基礎篇神經網路
- 網路基礎知識1
- 計算機基礎-網路基礎計算機
- 網路基礎之網路協議協議
- 網路基礎必備知識
- 計算機網路基礎-Socket計算機網路
- 神經網路基礎知識神經網路
- 八個網路基礎知識
- 【網路基礎】資料包生命
- 網路基礎之HTTP協議HTTP協議
- 網路基礎-常用網路測試工具
- Linux 筆記分享十七:網路基礎Linux筆記
- 計算機網路基礎(1)——概述計算機網路
- CCNA-Part1:網路基礎概念
- 網路基礎和 TCP、IP 協議TCP協議
- 7、卷積神經網路基礎卷積神經網路
- 網路基礎:TCP(3):TCP沾包TCP
- 計算機通訊與網路基礎計算機
- 神經網路基礎及Keras入門神經網路Keras
- Docker 網路基礎配置一(埠對映)Docker
- 一、《圖解HTTP》- WEB和網路基礎圖解HTTPWeb
- 深度學習教程 | 神經網路基礎深度學習神經網路
- 中級網路工程師--交換網路基礎工程師
- 網路虛擬化之linux虛擬網路基礎Linux
- 計算機網路基礎-2-物理層計算機網路
- 網路基礎 Modbus協議學習總結協議
- 神經網路基礎部件-BN層詳解神經網路
- 計算機網路基礎知識總結計算機網路
- 網路基礎知識 Network Address Translations 網路地址轉換
- 前端面試題 | 計算機網路基礎篇前端面試題計算機網路
- 筆記:網路基礎TCP、HTTP、HTTPS(HTTP+SSL)筆記TCPHTTP
- Java面試知識總結(一)-- 網路基礎Java面試
- 面試:計算機網路基礎詳解(一)面試計算機網路