Java - 網絡編程徹底總結

本文主要是本身在網絡編程方面的學習總結,先主要介紹計算機網絡方面的相關內容,包括計算機網絡基礎,OSI參考模型,TCP/IP協議簇,常見的網絡協議等等,在此基礎上,介紹Java中的網絡編程。git

1、概述
2、計算機網絡
   1.網絡協議
   2.網絡體系結構
3、OSI參考模型
4、TCP/IP參考模型
5、常見網絡協議
   1.TCP協議
   2.UDP協議
   3.HTTP協議
6、計網常見問題
7、Java網絡編程

1、概述

計算機網絡是經過傳輸介質、通訊設施和網絡通訊協議,把分散在不一樣地點的計算機設備互連起來,實現資源共享和數據傳輸的系統。網絡編程就就是編寫程序使聯網的兩個(或多個)設備(例如計算機)之間進行數據傳輸。Java語言對網絡編程提供了良好的支持,經過其提供的接口咱們能夠很方便地進行網絡編程。下面先對網絡編程的一些基礎知識進行介紹,最後給出使用Java語言進行網絡編程的實例。程序員

2、計算機網絡

計算機網絡20世紀60年代出現,經歷了20世紀70年代、80年代和90年代的發展,進入21世紀後,計算機網絡已經成爲信息社會的基礎設施,深刻到人類社會的方方面面,與人們的工做、學習和生活息息相關。編程

網絡協議瀏覽器

如同人與人之間相互交流是須要遵循必定的規矩同樣,計算機之間可以進行相互通訊是由於它們都共同遵照必定的規則,即網絡協議。緩存

網絡體系結構安全

計算機網絡是個複雜的系統,按照人們解決複雜問題的方法,把計算機網絡實現的功能分到不一樣的層次上,層與層之間用接口鏈接。通訊的雙方具備相同的層次,層次實現的功能由協議數據單元(PDU)來描述。不一樣系統中的同一層構成對等層,對等層之間經過對等層協議進行通訊,理解彼此定義好的規則和約定。服務器

計算機網絡體系結構是計算機網絡層次和協議的集合,網絡體系結構對計算機網絡實現的功能,以及網絡協議、層次、接口和服務進行了描述,但並不涉及具體的實現。接口是同一節點內相鄰層之間交換信息的鏈接處,也叫服務訪問點(SAP)。網絡


計算機網絡層次模型

3、OSI參考模型

前面咱們介紹了計算機網絡的體系結構,由於計算機網絡是個複雜的系統,因此把計算機網絡實現的功能分到不一樣的層次上,而計算機網絡體系結構是計算機網絡層次和協議的集合。那麼,計算機網絡如何進行分層呢?下面先介紹的是OSI參考模型。多線程

簡介併發

世界上第一個網絡體系結構由IBM公司提出(1974年,SNA),之後其餘公司也相繼提出本身的網絡體系結構如:Digital公司的DNA,美國國防部的TCP/IP等,多種網絡體系結構並存,其結果是若採用IBM的結構,只能選用IBM的產品,只能與同種結構的網絡互聯。

爲了促進計算機網絡的發展,國際標準化組織ISO於1977年成立了一個委員會,在現有網絡的基礎上,提出了不基於具體機型、操做系統或公司的網絡體系結構,稱爲開放系統互連參考模型,即OSI/RM (Open System Interconnection Reference Model)。OSI模型把網絡通訊的工做分爲7層,分別是物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。


OSI參考模型的7個層次

OSI模型層次功能

  • 物理層

物理層處於OSI的最底層,是整個開放系統的基礎。物理層涉及通訊信道上傳輸的原始比特流(bits),它的功能主要是爲數據端設備提供傳送數據的通路以及傳輸數據。

  • 數據鏈路層

數據鏈路層的主要任務是實現計算機網絡中相鄰節點之間的可靠傳輸,把原始的、有差錯的物理傳輸線路加上數據鏈路協議之後,構成邏輯上可靠的數據鏈路。須要完成的功能有鏈路管理、成幀、差錯控制以及流量控制等。其中成幀是對物理層的原始比特流進行界定,數據鏈路層也可以對幀的丟失進行處理。

  • 網絡層

網絡層涉及源主機節點到目的主機節點之間可靠的網絡傳輸,它須要完成的功能主要包括路由選擇、網絡尋址、流量控制、擁塞控制、網絡互連等。

  • 傳輸層

傳輸層起着承上啓下的做用,涉及源端節點到目的端節點之間可靠的信息傳輸。傳輸層須要解決跨越網絡鏈接的創建和釋放,對底層不可靠的網絡,創建鏈接時須要三次握手,釋放鏈接時須要四次揮手。

  • 會話層和表示層

會話層的主要功能是負責應用程序之間創建、維持和中斷會話,同時也提供對設備和結點之間的會話控制,協調系統和服務之間的交流,並經過提供單工、半雙工和全雙工3種不一樣的通訊方式,使系統和服務之間有序地進行通訊。

表示層關心所傳輸數據信息的格式定義,其主要功能是把應用層提供的信息變換爲可以共同理解的形式,提供字符代碼、數據格式、控制信息格式、加密等的統一表示。

  • 應用層

應用層爲OSI的最高層,是直接爲應用進程提供服務的。其做用是在實現多個系統應用進程相互通訊的同時,完成一系列業務處理所需的服務。

4、TCP/IP參考模型

OSI參考模型的初衷是提供全世界範圍的計算機網絡都要遵循的統一標準,可是因爲存在模型和協議自身的缺陷,遲遲沒有成熟的產品推出。TCP/IP協議在實踐中不斷完善和發展取得成功,做爲網絡的基礎,Internet的語言,能夠說沒有TCP/IP協議就沒有互聯網的今天。

簡介

TCP/IP,即Transmission Control Protocol/Internet Protocol的簡寫,中譯名爲傳輸控制協議/因特網互聯協議,是Internet最基本的協議、Internet國際互聯網絡的基礎。

TCP/IP協議是一個開放的網絡協議簇,它的名字主要取自最重要的網絡層IP協議和傳輸層TCP協議。TCP/IP協議定義了電子設備如何連入因特網,以及數據如何在它們之間傳輸的標準。TCP/IP參考模型採用4層的層級結構,每一層都呼叫它的下一層所提供的協議來完成本身的需求,這4個層次分別是:網絡接口層、互聯網層(IP層)、傳輸層(TCP層)、應用層。


OSI 和 TCP/IP模型對比

TCP/IP模型層次功能

  • 網絡接口層

TCP/IP協議對網絡接口層沒有給出具體的描述,網絡接口層對應着物理層和數據鏈路層。

  • 互聯網層 ( IP層 )

互聯網層是整個TCP/IP協議棧的核心。它的功能是把分組發往目標網絡或主機。同時,爲了儘快地發送分組,可能須要沿不一樣的路徑同時進行分組傳遞。所以,分組到達的順序和發送的順序可能不一樣,這就須要上層必須對分組進行排序。互聯網層除了須要完成路由的功能外,也能夠完成將不一樣類型的網絡(異構網)互連的任務。除此以外,互聯網層還須要完成擁塞控制的功能。  

  • 傳輸層 ( TCP層 )

TCP層負責在應用進程之間創建端到端的鏈接和可靠通訊,它只存在與端節點中。TCP層涉及兩個協議,TCP和UDP。其中,TCP協議提供面向鏈接的服務,提供按字節流的有序、可靠傳輸,能夠實現鏈接管理、差錯控制、流量控制、擁塞控制等。UDP協議提供無鏈接的服務,用於不須要或沒法實現面向鏈接的網絡應用中。

  • 應用層

應用層爲Internet中的各類網絡應用提供服務。

5、常見網絡協議

上面主要介紹了OSI參考模型和TCP/IP模型的相關內容,從下面這張圖能夠看出TCP/IP協議簇中不一樣的層次中有着不少不一樣的網絡協議,下面主要介紹傳輸層的TCP、UDP協議和應用層的HTTP協議。


 

TCP協議

  • 簡介

TCP(Transmission Control Protocol ,傳輸控制協議)是面向鏈接的傳輸層協議。TCP層是位於IP層之上,應用層之下的中間層。不一樣主機的應用層之間常常須要可靠的、像管道同樣的鏈接,可是IP層不提供這樣的流機制,而是提供不可靠的包交換。TCP協議採用字節流傳輸數據。

  • TCP報文段格式

TCP報文段包括協議首部和數據兩部分,協議首部的固定部分有20個字節,首部的固定部分後面是選項部分。


TCP報文段

下面是報文段首部各個字段的含義。

  1. 源端口號以及目的端口號,各佔2個字節,端口是傳輸層和應用層的服務接口,用於尋找發送端和接收端的進程,通常來說,經過端口號和IP地址,能夠惟一肯定一個TCP鏈接,在網絡編程中,一般被稱爲一個socket接口。
  2. 序號,佔4字節,用來標識從TCP發送端向TCP接收端發送的數據字節流。
  3. 確認序號,佔4字節,包含發送確認的一端所指望收到的下一個序號,所以,確認序號應該是上次已經成功收到數據字節序號加1.
  4. 數據偏移,佔4位,用於指出TCP首部長度,若不存在選項,則這個值爲20字節,數據偏移的最大值爲60字節。
  5. 保留字段佔6位,暫時可忽略,值全爲0
  6. 標誌位
    URG(緊急) : 爲1時代表緊急指針字段有效
    ACK(確認):爲1時代表確認號字段有效
    PSH(推送):爲1時接收方應儘快將這個報文段交給應用層
    RST(復位):爲1時代表TCP鏈接出現故障必須重建鏈接
    SYN(同步):在鏈接創建時用來同步序號
    FIN (終止): 爲1時代表發送端數據發送完畢要求釋放鏈接
  7. 接收窗口占2個字節,用於流量控制和擁塞控制,表示當前接收緩衝區的大小。在計算機網絡中,一般是用接收方的接收能力的大小來控制發送方的數據發送量。TCP鏈接的一端根據緩衝區大小肯定本身的接收窗口值,告訴對方,使對方能夠肯定發送數據的字節數。
  8. 校驗和佔2個字節,範圍包括首部和數據兩部分。
  9. 選項是可選的,默認狀況是不選。
  • 三次握手與四次揮手

TCP是面向鏈接的協議,所以每一個TCP鏈接都有3個階段:鏈接創建、數據傳送和鏈接釋放。鏈接創建經歷三個步驟,一般稱爲「三次握手」。

TCP三次握手過程以下:


TCP三次握手.jpg
  1. 第一次握手
    客戶機發送鏈接請求報文段到服務器,並進入SYN_SENT狀態,等待服務器確認。(SYN = 1,seq=x)
  2. 第二次握手
    服務器收到鏈接請求報文,若是贊成創建鏈接,向客戶機發回確認報文段,併爲該TCP鏈接分配TCP緩存和變量。(SYN=1,ACK=1,seq=y,ack=x+1)。
  3. 第三次握手
    客戶機收到服務器的確認報文段後,向服務器給出確認報文段,而且也要給該鏈接分配緩存和變量。此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。(ACK=1,seq=x+1,ack=y+1)。

TCP四次揮手過程以下:


四次揮手.png

因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的鏈接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另外一方執行被動關閉。

  1. TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送。
  2. 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。和SYN同樣,一個FIN將佔用一個序號。
  3. 服務器關閉客戶端的鏈接,發送一個FIN給客戶端。
  4. 客戶端發回ACK報文確認,並將確認序號設置爲收到序號加1。

UDP協議

  • 簡介

UDP,用戶數據報協議,英文全稱是User Datagram Protocol,它是TCP/IP協議簇中無鏈接的運輸層協議。

  • UDP協議格式

UDP格式

從圖中能夠看到,UDP協議十分簡單,它由兩部分組成:首部和數據。其中,首部僅有8個字節,包括源端口和目的端口,長度(UDP用於數據報的長度)、校驗和。

HTTP協議

  • 簡介

HTTP,超文本傳輸協議,英文全稱是Hypertext Transfer Protocol,它是互聯網上應用最爲普遍的一種網絡協議。HTTP是一種應用層協議,它是基於TCP協議之上的請求/響應式的協議,即一個客戶端與服務器創建鏈接後,向服務器發送一個請求;服務器接到請求後,給予相應的響應信息。HTTP協議默認的端口號爲80.

如今使用的HTTP協議是HTTP/1.1版本,1997年以前採用的是HTTP1.0版本。HTTP鏈接在1.0版本中採用非持續鏈接工做方式,1.1版本採用的是持續鏈接工做方式,持續鏈接是指服務器在發送響應後仍然在一段時間內保持這條由TCP運輸層協議創建起來的鏈接,使客戶機和服務器能夠繼續在這條鏈接上傳輸HTTP報文。

是否採用持續鏈接工做方式,1.0中默認是關閉的,須要在HTTP頭加入"Connection:Keep-Alive",才能啓用Keep-Alive。HTTP1.1中默認啓用Keep-Alive,若是加入"Connection:close",才關閉。目前大部分瀏覽器都是用HTTP1.1協議,也就是說默認都會發起Keep-Alive的鏈接請求了,因此是否能完成一個完整的Keep- Alive鏈接就看服務器設置狀況。

  • HTTP報文

HTTP協議是基於TCP協議之上的請求/響應式協議,下面主要介紹HTTP報文的格式,HTTP報文主要有請求報文和響應報文兩種。首先看請求報文的格式:


HTTP請求報文格式

HTTP請求報文由請求行、首部行和實體主體組成,由瀏覽器發送給服務器。上面這張圖中SP表示空格,cr lf表示回車和換行。


HTTP響應報文格式

上面這張圖是HTTP響應報文,它由狀態行、首部行和實體主體組成。下面兩張圖是在谷歌瀏覽器內訪問服務器查看的HTTP請求和響應。


HTTP請求報文例子

HTTP響應報文例子
  • HTTP請求方法和響應狀態碼

在上面的HTTP請求報文例子中,咱們能夠看到請求方法是GET,這表示請求讀取由URL所標誌的信息,除了GET,還有其它幾種經常使用的方法。


HTTP請求報文的一些方法

在HTTP響應報文的例子中,咱們能夠看到狀態碼是200,表示響應成功。下表是其它狀態碼,總共5大類,33種。


HTTP響應報文的狀態碼

HTTPS和HTTP的區別

HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。它是一個URI scheme(抽象標識符體系),句法類同http:體系。用於安全的HTTP數據傳輸。https:URL代表它使用了HTTP,但HTTPS存在不一樣於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。

超文本傳輸協議HTTP協議被用於在Web瀏覽器和網站服務器之間傳遞信息。HTTP協議以明文方式發送內容,不提供任何方式的數據加密,若是攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文,就能夠直接讀懂其中的信息,所以HTTP協議不適合傳輸一些敏感信息,好比信用卡號、密碼等。

爲了解決HTTP協議的這一缺陷,須要使用另外一種協議:安全套接字層超文本傳輸協議HTTPS。爲了數據傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證服務器的身份,併爲瀏覽器和服務器之間的通訊加密。

HTTPS和HTTP的區別主要爲如下四點:一、https協議須要到ca申請證書,通常免費證書不多,須要交費。二、http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

6、常見問題

到這裏,關於計算機網絡部分的總結內容就結束了,下面是幾個常見的問題,彙總在這裏。

  1. OSI參考模型的分爲哪幾層,每層的功能?
    OSI,開放系統互連參考模型,它的7個層次自頂到下依次爲應用層,表示層,會話層,傳輸層,網絡層,數據鏈路層和物理層。各層的功能見文章開始。

  2. TCP協議和UDP協議的區別?
    TCP協議是傳輸控制協議,UDP協議是用戶數據報協議,二者都是傳輸層的協議,主要區別在於前者是可靠的,面向鏈接的協議,後者是不可靠的,無鏈接的協議。其它的區別還有,TCP協議傳輸速度慢,UDP經常使用於一次性傳輸比較少許數據的網絡應用。

  3. TCP三次握手爲何不能是兩次?
    主要是防止兩次握手狀況下已經失效的鏈接請求報文段忽然又傳送到服務端而產生錯誤。例如,客戶機A向服務器B發送TCP鏈接請求,第一個鏈接請求報文在網絡的某個節點長時間滯留,A超時後認爲報文丟失,因而再重傳一次鏈接請求,B收到後創建鏈接。數據傳輸完畢後雙方斷開鏈接,而這時以前滯留的鏈接請求到達了服務端B,而B認爲A又發來鏈接請求。若是兩次握手創建鏈接,A並沒有鏈接請求,形成B的資源浪費。

  4. HTTP請求的GET方法和POST方法的區別?
    GET和POST是HTTP請求的兩種方法,主要區別在於GET方法是請求讀取由URL所標誌的信息,POST是給服務器添加信息。點擊查看更多

  5. 在瀏覽器中輸入網址到顯示出頁面的整個過程?
    (1) 輸出包含域名的網址 (2) 瀏覽器向DNS請求解析域名對應的IP地址 (3) 域名系統DNS解析出域名對應的IP地址 (4) 瀏覽器與該服務器創建TCP鏈接 (5) 瀏覽器發送HTTP請求 (6) 服務器經過HTTP響應把頁面文件發送給瀏覽器 (7) TCP鏈接釋放 (8) 瀏覽器解釋文件,並顯示

7、Java網絡編程

Java的網絡編程主要涉及到的內容是Socket編程,那麼什麼是Socket呢?簡單地說,Socket,套接字,就是兩臺主機之間邏輯鏈接的端點。TPC/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據。Socket,本質上就是一組接口,是對TCP/IP協議的封裝和應用(程序員層面上)。

總體流程

Socket編程主要涉及到客戶端和服務器端兩個方面,首先是在服務器端建立一個服務器套接字(ServerSocket),並把它附加到一個端口上,服務器從這個端口監聽鏈接。端口號的範圍是0到65536,可是0到1024是爲特權服務保留的端口號,咱們能夠選擇任意一個當前沒有被其餘進程使用的端口。

客戶端請求與服務器進行鏈接的時候,根據服務器的域名或者IP地址,加上端口號,打開一個套接字。當服務器接受鏈接後,服務器和客戶端之間的通訊就像輸入輸出流同樣進行操做。


 

實例一

下面是一個客戶端和服務器端進行數據交互的簡單例子,客戶端輸入正方形的邊長,服務器端接收到後計算面積並返回給客戶端,經過這個例子能夠初步對Socket編程有個把握。

  • 服務器端
public class SocketServer {

    public static void main(String[] args) throws IOException {

        // 端口號
        int port = 7000;
        // 在端口上建立一個服務器套接字
        ServerSocket serverSocket = new ServerSocket(port);
        // 監聽來自客戶端的鏈接
        Socket socket = serverSocket.accept();

        DataInputStream dis = new DataInputStream(
                new BufferedInputStream(socket.getInputStream()));

        DataOutputStream dos = new DataOutputStream(
                new BufferedOutputStream(socket.getOutputStream()));

        do {

            double length = dis.readDouble();
            System.out.println("服務器端收到的邊長數據爲:" + length);
            double result = length * length;
            dos.writeDouble(result);
            dos.flush();

        } while (dis.readInt() != 0);

        socket.close();
        serverSocket.close();
    }
}
  • 客戶端
public class SocketClient {

    public static void main(String[] args) throws UnknownHostException, IOException {

        int port = 7000;

        String host = "localhost";

        // 建立一個套接字並將其鏈接到指定端口號
        Socket socket = new Socket(host, port);

        DataInputStream dis = new DataInputStream(
                new BufferedInputStream(socket.getInputStream()));

        DataOutputStream dos = new DataOutputStream(
                new BufferedOutputStream(socket.getOutputStream()));

        Scanner sc = new Scanner(System.in);

        boolean flag = false;

        while (!flag) {

            System.out.println("請輸入正方形的邊長:");
            double length = sc.nextDouble();

            dos.writeDouble(length);
            dos.flush();

            double area = dis.readDouble();

            System.out.println("服務器返回的計算面積爲:" + area);

            while (true) {

                System.out.println("繼續計算?(Y/N)");

                String str = sc.next();

                if (str.equalsIgnoreCase("N")) {
                    dos.writeInt(0);
                    dos.flush();
                    flag = true;
                    break;
                } else if (str.equalsIgnoreCase("Y")) {
                    dos.writeInt(1);
                    dos.flush();
                    break;
                }
            }
        }

        socket.close();
    }
}

實例二

能夠看到上面的服務器端程序和客戶端程序是一對一的關係,爲了能讓一個服務器端程序能同時爲多個客戶提供服務,可使用多線程機制,每一個客戶端的請求都由一個獨立的線程進行處理。下面是改寫後的服務器端程序。

public class SocketServerM {

    public static void main(String[] args) throws IOException {

        int port = 7000;
        int clientNo = 1;

        ServerSocket serverSocket = new ServerSocket(port);

        // 建立線程池
        ExecutorService exec = Executors.newCachedThreadPool();

        try {

            while (true) {
                Socket socket = serverSocket.accept();
                exec.execute(new SingleServer(socket, clientNo));
                clientNo++;
            }

        } finally {
            serverSocket.close();
        }

    }
}

class SingleServer implements Runnable {

    private Socket socket;
    private int clientNo;

    public SingleServer(Socket socket, int clientNo) {
        this.socket = socket;
        this.clientNo = clientNo;
    }

    @Override
    public void run() {

        try {

            DataInputStream dis = new DataInputStream(
                    new BufferedInputStream(socket.getInputStream()));

            DataOutputStream dos = new DataOutputStream(
                    new BufferedOutputStream(socket.getOutputStream()));

            do {

                double length = dis.readDouble();
                System.out.println("從客戶端" + clientNo + "接收到的邊長數據爲:" + length);
                double result = length * length;
                dos.writeDouble(result);
                dos.flush();

            } while (dis.readInt() != 0);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("與客戶端" + clientNo + "通訊結束");
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

上面改進後的服務器端代碼能夠支持不斷地併發響應網絡中的客戶請求。關鍵的地方在於多線程機制的運用,同時利用線程池能夠改善服務器程序的性能。

做者:塵語凡心連接:http://www.jianshu.com/p/ae5e1cee5b04來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索