日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络基础(二)及HTTP协议

發布時間:2024/4/11 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络基础(二)及HTTP协议 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網絡基礎(二)及HTTP協議

文章目錄

  • 網絡基礎(二)及HTTP協議
    • 一、HTTP協議
    • 二、端口
    • 三、udp協議
    • 四、tcp協議

一、HTTP協議

  • 1 . 什么是url?
  • 平時我們俗稱的 “網址” 其實就是說的 URL

  • 2.http協議的格式

  • http請求:

- 首行: [方法] + [url] + [版本]- Header: 請求的屬性, 冒號分割的鍵值對;每組屬性之間使用\n分隔;遇到空行表示Header部分結束- 空行- Body: 空行后面的內容都是Body. Body允許為空字符串. 如果Body存在, 則在Header中會有一個Content-Length屬性來標識Body的長度;
  • http響應:
- 首行: [版本號] + [狀態碼] + [狀態碼解釋] - Header: 請求的屬性,冒號分割的鍵值對;每組屬性之間使用\n分隔;遇到空行表示Header部分結束 - 空行- Body: 空行后面的內容都是Body.Body允許為空字符串. 如果Body存在, 則在Header中會有一個 Content-Length屬性來標識Body的長度;如果服務器返回了一個html頁面, 那么html頁面內容就是在 body中.
  • http常見的Header:
- Content-Type: 數據類型(text/html等) - Content-Length: Body的長度 - Host:客戶端告知服務器, 所請求的資源是在哪個主機的哪個端口上; - User-Agent: 聲明用戶的操作系統和瀏覽器版本信息; - referer:當前頁面是從哪個頁面跳轉過來的;- location: 搭配3xx狀態碼使用, 告訴客戶端接下來要去哪里訪問; Cookie:用于在客戶端存儲少量信息. 通常用于實現會話(session)的功能
  • http的方法:
方法說明
GET獲取資源
POST傳輸實體主體
PUT傳輸文件
HEAD獲得報文首部
DELETE刪除文件
OPTIONS詢問支持的方法
TRACE追蹤路徑
CONNECT要求用隧道協議鏈接代理
LINK建立和資源之間的聯系
UNLINE斷開鏈接關系
  • 3.常見的HTTP服務器
#include <sys/socket.h>#include <netinet/in.h> #include <arpa/inet.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <stdlib.h>void Usage() {printf("usage: ./server [ip] [port]\n");}int main(int argc, char* argv[]) {if (argc != 3) {Usage();return 1;}int fd = socket(AF_INET, SOCK_STREAM, 0);if (fd < 0){perror("socket");return 1;}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(argv[1]);addr.sin_port = htons(atoi(argv[2]));int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));if (ret < 0){perror("bind");return 1;}ret = listen(fd, 10);if (ret < 0){perror("listen");return 1;}for (;;) {struct sockaddr_in client_addr;socklen_t len;int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);if (client_fd < 0){perror("accept");continue;}char input_buf[1024 * 10] = {0}; // 用一個足夠大的緩沖區直接把數據讀完.ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);if (read_size < 0){return 1;}printf("[Request] %s", input_buf);char buf[1024] = {0}; const char* hello = "<h1>hello world</h1>";sprintf(buf, "HTTP/1.0 200 OK\nContent-Length:%lu\n\n%s", strlen(hello), hello);write(client_fd, buf, strlen(buf));}return 0; }

二、端口

  • 1.什么是端口號?
  • 端口號(Port)標識了一個主機上進行通信的不同的應用程序;
  • 2.端口號范圍劃分
  • 0 - 1023: 知名端口號, HTTP, FTP, SSH等這些廣為使用的應用層協議, 他們的端口號都是固定的
  • 1024 - 65535: 操作系統動態分配的端口號. 客戶端程序的端口號, 就是由操作系統從這個范圍分配的
ssh服務器, 使用22端口 ftp服務器, 使用21端口 telnet服務器, 使用23端口 http服務器, 使用80端口 https服務器, 使用443
  • **==一個進程是可以bind多個端口號
  • 一個端口號是通常不可以可以被多個進程bind==**

三、udp協議

  • 1 . UDP協議端格式

  • 16位UDP長度, 表示整個數據報(UDP首部+UDP數據)的最大長度;
  • 如果校驗和出錯, 就會直接丟棄;
  • 2.udp的特點(寄信)
  • 無連接: 知道對端的IP和端口號就直接進行傳輸, 不需要建立連接;
  • 不可靠: 沒有確認機制, 沒有重傳機制;如果因為網絡故障該段無法發到對方, UDP協議層也不會給應用層 返回任何錯誤信息; 面向數據報: 不能夠靈活的控制讀寫數據的次數和數量;
  • 面向數據報,應用層交給UDP多長的報文, UDP原樣發送, 既不會拆分, 也不會合并
  • UDP的緩沖區
    UDP沒有真正意義上的 發送緩沖區. 調用sendto會直接交給內核, 由內核將數據傳給網絡層協議進行后續的傳輸動作;UDP具有接收緩沖區. 但是這個接收緩沖區不能保證收到的UDP報的順序和發送UDP報的順序一致; 如果緩沖區滿了, 再到達的UDP數據就會被丟棄
  • UDP使用注意事項: 我們注意到, UDP協議首部中有一個16位的最大長度. 也就是說一個UDP能傳輸的數據最大長度是64K(包含UDP首部). 然而64K在當今的互聯網環境下, 是一個非常小的數字. 如果我們需要傳輸的數據超過64K, 就需要在應用層手動的分包, 多次發送, 并在接收端手動拼裝;

四、tcp協議

  • 1.TCP協議段格式

  • 源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去;
  • 32位序號/32位確認號:
  • 4位TCP報頭長度:表示該TCP頭部有多少個32位bit(有多少個4字節); 所以TCP頭部最大長度是15 * 4 = 60
  • 6位標志位
URG: 緊急指針是否有效 ACK: 確認號是否有效 PSH: 提示接收端應用程序立刻從TCP緩沖區把數據讀走 RST: 對方要求重新建立連接; 我們把攜帶RST標識的稱為復位報文段 SYN: 請求建立連接; 我們把攜帶SYN標識的稱為同步報文段 FIN: 通知對方, 本端要關閉了, 我們稱攜帶FIN標識的為結束報文段
  • 16位窗口大小

  • 16位校驗和: 發送端填充, CRC校驗. 接收端校驗不通過, 則認為數據有問題. 此處的檢驗和不光包含TCP首部, 也包含TCP數據部分.

  • 16位緊急指針: 標識哪部分數據是緊急數據;

  • 40字節頭部選項: 暫時忽略

  • 2.TCP中重要的機制

  • 確認應答(ACK)機制

  • TCP將每個字節的數據都進行了編號. 即為序列號
  • 每一個ACK都帶有對應的確認序列號, 意思是告訴發送者, 我已經收到了哪些數據;下一次你從哪里開始發

超時重傳機制

  • 主機A發送數據給B之后, 可能因為網絡擁堵等原因, 數據無法到達主機B;
  • 如果主機A在一個特定時間間隔內沒有收到B發來的確認應答, 就會進行重發

但是, 主機A未收到B發來的確認應答, 也可能是因為ACK丟失了


因此主機B會收到很多重復數據. 那么TCP協議需要能夠識別出那些包是重復的包, 并且把重復的丟棄掉.這時候我們可以利用前面提到的序列號, 就可以很容易做到去重的效果

超時時間的確定:

  • 最理想的情況下, 找到一個最小的時間, 保證 “確認應答一定能在這個時間內返回”. 但是這個時間的長短, 隨著網絡環境的不同, 是有差異的. 如果超時時間設的太長, 會影響整體的重傳效率; 如果超時時間設的太短, 有可能會頻繁發送重復的包
  • Linux中(BSD Unix和Windows也是如此), 超時以500ms為一個單位進行控制, 每次判定超時重發的超時時間都是500ms的整數倍.
  • 如果重發一次之后, 仍然得不到應答, 等待 2500ms 后再進行重傳如果仍然得不到應答, 等待 4500ms 進行重傳.
  • 依次類推, 以指數形式遞增.
  • 累計到一定的重傳次數, TCP認為網絡或者對端主機出現異常, 強制關閉連接

連接管理機制

就是tcp協議的三次握手四次揮手
詳解三次握手四次揮手

滑動窗口

確認應答策略, 對每一個發送的數據段, 都要給一個ACK確認應答. 收到ACK后再發送下一個數據段.這樣做有一個比較大的缺點, 就是性能較差. 尤其是數據往返的時間較長的時候

  • 窗口大小指的是無需等待確認應答而可以繼續發送數據的最大值. 上圖的窗口大小就是4000個字節(四個 段).
  • 發送前四個段的時候, 不需要等待任何ACK, 直接發送;
  • 收到第一個ACK后, 滑動窗口向后移動, 繼續發送第五個段的數據; 依次類推;
  • 操作系統內核為了維護這個滑動窗口, 需要開辟 發送緩沖區 來錄當前還有哪些數據沒有應答; 只有確認應答過的數據, 才能從緩沖區刪掉;
  • 窗口越大, 則網絡的吞吐率就越高;

如果滑動窗口發生丟包,怎么重傳?

  • 情況一: 數據包已經抵達, ACK被丟了
    這種情況下, 部分ACK丟了并不要緊, 因為可以通過后續的ACK進行確認;(更高級的數據序列號的確認)

  • 情況二: 數據包就直接丟了

  • 當某一段報文段丟失之后, 發送端會一直收到 1001 這樣的ACK, 就像是在提醒發送端 “我想要的是 1001” 一樣;

  • 如果發送端主機連續三次收到了同樣一個 “1001” 這樣的應答, 就會將對應的數據 1001 - 2000 重新發送;

  • 這個時候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因為2001 - 7000)接收端其實之前就已經收到了, 被放到了接收端操作系統內核的接收緩沖區中

這種機制被稱為 “高速重發控制”(也叫 “快重傳”)

流量控制

接收端處理數據的速度是有限的. 如果發送端發的太快, 導致接收端的緩沖區被打滿, 這個時候如果發送端繼續發送,就會造成丟包, 繼而引起丟包重傳等等一系列連鎖反應. 因此TCP支持根據接收端的處理能力, 來決定發送端的發送速度. 這個機制就叫做流量控制

  • 接收端將自己可以接收的緩沖區大小放入 TCP 首部中的 “窗口大小” 字段, 通過ACK端通知發送端
  • 窗口大小字段越大, 說明網絡的吞吐量越高;
  • 接收端一旦發現自己的緩沖區快滿了, 就會將窗口大小設置成一個更小的值通知給發送端;
  • 發送端接受到這個窗口之后, 就會減慢自己的發送速度;
  • 如果接收端緩沖區滿了, 就會將窗口置為0; 這時發送方不再發送數據, 但是需要定期發送一個窗口探測數據段, 使接收端把窗口大小告訴發送端

擁塞控制

  • 雖然TCP有了滑動窗口這個大殺器, 能夠高效可靠的發送大量的數據. 但是如果在剛開始階段就發送大量的數據, 仍然可能引發問題.

  • 因為網絡上有很多的計算機, 可能當前的網絡狀態就已經比較擁堵. 在不清楚當前網絡狀態下, 貿然發送大量的數據是很有可能引起雪上加霜的.

  • TCP引入 慢啟動 機制, 先發少量的數據, 探探路, 摸清當前的網絡擁堵狀態, 再決定按照多大的速度傳輸數據

  • 為了不增長的那么快, 因此不能使擁塞窗口單純的加倍

  • 此處引入一個叫做慢啟動的閾值

  • 當擁塞窗口超過這個閾值的時候, 不再按照指數方式增長, 而是按照線性方式增長

  • 當TCP開始啟動的時候, 慢啟動閾值等于窗口最大值

  • 在每次超時重發的時候, 慢啟動閾值會變成原來的一半, 同時擁塞窗口置回1

延遲應答

如果接收數據的主機立刻返回ACK應答, 這時候返回的窗口可能比較小

  • 假設接收端緩沖區為1M. 一次收到了500K的數據; 如果立刻應答, 返回的窗口就是500K;
  • 但實際上可能處理端處理的速度很快, 10ms之內就把500K數據從緩沖區消費掉了;
  • 在這種情況下, 接收端處理還遠沒有達到自己的極限, 即使窗口再放大一些, 也能處理過來;
  • 如果接收端稍微等一會再應答, 比如等待200ms再應答, 那么這個時候返回的窗口大小就是1M;

一定要記得, 窗口越大, 網絡吞吐量就越大, 傳輸效率就越高. 我們的目標是在保證網絡不擁塞的情況下盡量提高傳輸效率;

捎帶應答

在延遲應答的基礎上, 我們發現, 很多情況下, 客戶端服務器在應用層也是 “一發一收” 的. 意味著客戶端給服務器說了 “How are you”, 服務器也會給客戶端回一個 “Fine, thank you”;那么這個時候ACK就可以搭順風車, 和服務器回應的 “Fine, thank you” 一起回給客戶端

面向字節流

創建一個TCP的socket, 同時在內核中創建一個 發送緩沖區 和一個 接收緩沖區;

  • 調用write時, 數據會先寫入發送緩沖區中;
  • 如果發送的字節數太長, 會被拆分成多個TCP的數據包發出;
  • 如果發送的字節數太短, 就會先在緩沖區里等待, 等到緩沖區長度差不多了, 或者其他合適的時機發送出去;
  • 接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩沖區;然后應用程序可以調用read從接收緩沖區拿數據;
  • 另一方面, TCP的一個連接, 既有發送緩沖區, 也有接收緩沖區, 那么對于這一個連接, 既可以讀數據, 也可以寫數據. 這個概念叫做 全雙工
  • 由于緩沖區的存在, TCP程序的讀和寫不需要一一匹配, 例如:
    寫100個字節數據時, 可以調用一次write寫100個字節, 也可以調100次write, 每次寫一個字節;
  • 讀100個字節數據時, 也完全不需要考慮寫的時候是怎么寫的, 既可以一次read 100個字節, 也可以一次read一個字節,
    重復100次

粘包問題

  • 首先要明確, 粘包問題中的 “包” , 是指的應用層的數據包.
  • 在TCP的協議頭中, 沒有如同UDP一樣的 “報文長度” 這樣的字段, 但是有一個序號這樣的字段.
  • 站在傳輸層的角度, TCP是一個一個報文過來的. 按照序號排好序放在緩沖區中.
  • 站在應用層的角度, 看到的只是一串連續的字節數據.
  • 那么應用程序看到了這么一連串的字節數據, 就不知道從哪個部分開始到哪個部分, 是一個完整的應用層數據包

那么如何避免粘包問題呢? 歸根結底就是一句話, 明確兩個包之間的邊界

  • 對于定長的包, 保證每次都按固定大小讀取即可; 是固定大小的, 那么就從緩沖區從頭開始按sizeof(Request)依次讀取即可;
  • 對于變長的包, 可以在包頭的位置, 約定一個包總長度的字段, 從而就知道了包的結束位置;
  • 對于變長的包, 還可以在包和包之間使用明確的分隔符(應用層協議, 是程序猿自己來定的, 只要保證分隔符不和正文沖突即可)

對于UDP協議來說, 是否也存在 “粘包問題” 呢?

  • 對于UDP, 如果還沒有上層交付數據, UDP的報文長度仍然在. 同時, UDP是一個一個把數據交付給應用 層. 就有很明確的數據邊界.
  • 站在應用層的站在應用層的角度, 使用UDP的時候, 要么收到完整的UDP報文, 要么不收. 不會出現"半個"的情況

總結

以上是生活随笔為你收集整理的网络基础(二)及HTTP协议的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。