日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > CPP開發(fā)者
[導讀]↓推薦關注↓上篇:《重磅干貨|五萬字長文總結(jié)C/C知識(上)》網(wǎng)絡層IP(InternetProtocol,網(wǎng)際協(xié)議)是為計算機網(wǎng)絡相互連接進行通信而設計的協(xié)議。ARP(AddressResolutionProtocol,地址解析協(xié)議)ICMP(InternetControlMe...


推薦關注↓



上篇:重磅干貨 | 五萬字長文總結(jié) C/C 知識(上)

網(wǎng)絡層

  • IP(Internet Protocol,網(wǎng)際協(xié)議)是為計算機網(wǎng)絡相互連接進行通信而設計的協(xié)議。

  • ARP(Address Resolution Protocol,地址解析協(xié)議)

  • ICMP(Internet Control Message Protocol,網(wǎng)際控制報文協(xié)議)

  • IGMP(Internet Group Management Protocol,網(wǎng)際組管理協(xié)議)

IP 網(wǎng)際協(xié)議

IP 地址分類:

  • IP 地址 ::= {<網(wǎng)絡號>,<主機號>}


IP 地址類別網(wǎng)絡號網(wǎng)絡范圍主機號IP 地址范圍
A 類8bit,第一位固定為 00 —— 12724bit1.0.0.0 —— 127.255.255.255
B 類16bit,前兩位固定為 10128.0 —— 191.25516bit128.0.0.0 —— 191.255.255.255
C 類24bit,前三位固定為 110192.0.0 —— 223.255.2558bit192.0.0.0 —— 223.255.255.255
D 類前四位固定為 1110,后面為多播地址


E 類前五位固定為 11110,后面保留為今后所用


應用:

  • PING(Packet InterNet Groper,分組網(wǎng)間探測)測試兩個主機之間的連通性


      • TTL(Time To Live,生存時間)該字段指定 IP 包被路由器丟棄之前允許通過的最大網(wǎng)段數(shù)量

內(nèi)部網(wǎng)關協(xié)議

  • RIP(Routing Information Protocol,路由信息協(xié)議)

  • OSPF(Open Sortest Path First,開放最短路徑優(yōu)先)

外部網(wǎng)關協(xié)議

  • BGP(Border Gateway Protocol,邊界網(wǎng)關協(xié)議)

IP多播

  • IGMP(Internet Group Management Protocol,網(wǎng)際組管理協(xié)議)

  • 多播路由選擇協(xié)議

VPN 和 NAT

  • VPN(Virtual Private Network,虛擬專用網(wǎng))

  • NAT(Network Address Translation,網(wǎng)絡地址轉(zhuǎn)換)

路由表包含什么?

  1. 網(wǎng)絡 ID(Network ID, Network number):就是目標地址的網(wǎng)絡 ID。

  2. 子網(wǎng)掩碼(subnet mask):用來判斷 IP 所屬網(wǎng)絡

  3. 下一跳地址/接口(Next hop / interface):就是數(shù)據(jù)在發(fā)送到目標地址的旅途中下一站的地址。其中 interface 指向 next hop(即為下一個 route)。一個自治系統(tǒng)(AS, Autonomous system)中的 route 應該包含區(qū)域內(nèi)所有的子網(wǎng)絡,而默認網(wǎng)關(Network id:?0.0.0.0, Netmask:?0.0.0.0)指向自治系統(tǒng)的出口。

根據(jù)應用和執(zhí)行的不同,路由表可能含有如下附加信息:

  1. 花費(Cost):就是數(shù)據(jù)發(fā)送過程中通過路徑所需要的花費。

  2. 路由的服務質(zhì)量

  3. 路由中需要過濾的出/入連接列表

運輸層

協(xié)議:

  • TCP(Transmission Control Protocol,傳輸控制協(xié)議)

  • UDP(User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議)

端口:

應用程序FTPTELNETSMTPDNSTFTPHTTPHTTPSSNMP
端口號212325536980443161

受限于公眾號文章字數(shù)限制,后續(xù)部分請看【今天的第二篇推文】,


TCP

  • TCP(Transmission Control Protocol,傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,其傳輸?shù)膯挝皇菆笪亩巍?/span>

特征:

  • 面向連接

  • 只能點對點(一對一)通信

  • 可靠交互

  • 全雙工通信

  • 面向字節(jié)流

TCP 如何保證可靠傳輸:

  • 確認和超時重傳

  • 數(shù)據(jù)合理分片和排序

  • 流量控制

  • 擁塞控制

  • 數(shù)據(jù)校驗


TCP 首部

TCP:狀態(tài)控制碼(Code,Control Flag),占 6 比特,含義如下:

  • URG:緊急比特(urgent),當 URG=1 時,表明緊急指針字段有效,代表該封包為緊急封包。它告訴系統(tǒng)此報文段中有緊急數(shù)據(jù),應盡快傳送(相當于高優(yōu)先級的數(shù)據(jù)), 且上圖中的 Urgent Pointer 字段也會被啟用。

  • ACK:確認比特(Acknowledge)。只有當 ACK=1 時確認號字段才有效,代表這個封包為確認封包。當 ACK=0 時,確認號無效。

  • PSH:(Push function)若為 1 時,代表要求對方立即傳送緩沖區(qū)內(nèi)的其他對應封包,而無需等緩沖滿了才送。

  • RST:復位比特(Reset),當 RST=1 時,表明 TCP 連接中出現(xiàn)嚴重差錯(如由于主機崩潰或其他原因),必須釋放連接,然后再重新建立運輸連接。

  • SYN:同步比特(Synchronous),SYN 置為 1,就表示這是一個連接請求或連接接受報文,通常帶有 SYN 標志的封包表示『主動』要連接到對方的意思。

  • FIN:終止比特(Final),用來釋放一個連接。當 FIN=1 時,表明此報文段的發(fā)送端的數(shù)據(jù)已發(fā)送完畢,并要求釋放運輸連接。

UDP

  • UDP(User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議)是 OSI(Open System Interconnection 開放式系統(tǒng)互聯(lián)) 參考模型中一種無連接的傳輸層協(xié)議,提供面向事務的簡單不可靠信息傳送服務,其傳輸?shù)膯挝皇怯脩魯?shù)據(jù)報。

特征:

  • 無連接

  • 盡最大努力交付

  • 面向報文

  • 沒有擁塞控制

  • 支持一對一、一對多、多對一、多對多的交互通信

  • 首部開銷小


TCP 與 UDP 的區(qū)別

  1. TCP 面向連接,UDP 是無連接的;

  2. TCP 提供可靠的服務,也就是說,通過 TCP 連接傳送的數(shù)據(jù),無差錯,不丟失,不重復,且按序到達;UDP 盡最大努力交付,即不保證可靠交付

  3. TCP 的邏輯通信信道是全雙工的可靠信道;UDP 則是不可靠信道

  4. 每一條 TCP 連接只能是點到點的;UDP 支持一對一,一對多,多對一和多對多的交互通信

  5. TCP 面向字節(jié)流(可能出現(xiàn)黏包問題),實際上是 TCP 把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流;UDP 是面向報文的(不會出現(xiàn)黏包問題)

  6. UDP 沒有擁塞控制,因此網(wǎng)絡出現(xiàn)擁塞不會使源主機的發(fā)送速率降低(對實時應用很有用,如 IP 電話,實時視頻會議等)

  7. TCP 首部開銷20字節(jié);UDP 的首部開銷小,只有 8 個字節(jié)

TCP 黏包問題

原因
TCP 是一個基于字節(jié)流的傳輸服務(UDP 基于報文的),“流” 意味著 TCP 所傳輸?shù)臄?shù)據(jù)是沒有邊界的。所以可能會出現(xiàn)兩個數(shù)據(jù)包黏在一起的情況。

解決
  • 發(fā)送定長包。如果每個消息的大小都是一樣的,那么在接收對等方只要累計接收數(shù)據(jù),直到數(shù)據(jù)等于一個定長的數(shù)值就將它作為一個消息。

  • 包頭加上包體長度。包頭是定長的 4 個字節(jié),說明了包體的長度。接收對等方先接收包頭長度,依據(jù)包頭長度來接收包體。

  • 在數(shù)據(jù)包之間設置邊界,如添加特殊符號 \r\n 標記。FTP 協(xié)議正是這么做的。但問題在于如果數(shù)據(jù)正文中也含有 \r\n,則會誤判為消息的邊界。

  • 使用更加復雜的應用層協(xié)議。

TCP 流量控制

概念
流量控制(flow control)就是讓發(fā)送方的發(fā)送速率不要太快,要讓接收方來得及接收。

方法

利用可變窗口進行流量控制

TCP 擁塞控制

概念
擁塞控制就是防止過多的數(shù)據(jù)注入到網(wǎng)絡中,這樣可以使網(wǎng)絡中的路由器或鏈路不致過載。

方法
  • 慢開始( slow-start )

  • 擁塞避免( congestion avoidance )

  • 快重傳( fast retransmit )

  • 快恢復( fast recovery?


TCP 傳輸連接管理

因為 TCP 三次握手建立連接、四次揮手釋放連接很重要,所以附上《計算機網(wǎng)絡(第 7 版)-謝希仁》書中對此章的詳細描述:https://github.com/huihut/interview/blob/master/images/TCP-transport-connection-management.png

TCP 三次握手建立連接
UDP 報文
【TCP 建立連接全過程解釋】

  1. 客戶端發(fā)送 SYN 給服務器,說明客戶端請求建立連接;

  2. 服務端收到客戶端發(fā)的 SYN,并回復 SYN ACK 給客戶端(同意建立連接);

  3. 客戶端收到服務端的 SYN ACK 后,回復 ACK 給服務端(表示客戶端收到了服務端發(fā)的同意報文);

  4. 服務端收到客戶端的 ACK,連接已建立,可以數(shù)據(jù)傳輸。

TCP 為什么要進行三次握手?
【答案一】因為信道不可靠,而 TCP 想在不可靠信道上建立可靠地傳輸,那么三次通信是理論上的最小值。(而 UDP 則不需建立可靠傳輸,因此 UDP 不需要三次握手。)

Google Groups . TCP 建立連接為什么是三次握手?{技術}{網(wǎng)絡通信}

【答案二】因為雙方都需要確認對方收到了自己發(fā)送的序列號,確認過程最少要進行三次通信。

知乎 . TCP 為什么是三次握手,而不是兩次或四次?

【答案三】為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產(chǎn)生錯誤。

《計算機網(wǎng)絡(第 7 版)-謝希仁》


【TCP 釋放連接全過程解釋】

  1. 客戶端發(fā)送 FIN 給服務器,說明客戶端不必發(fā)送數(shù)據(jù)給服務器了(請求釋放從客戶端到服務器的連接);

  2. 服務器接收到客戶端發(fā)的 FIN,并回復 ACK 給客戶端(同意釋放從客戶端到服務器的連接);

  3. 客戶端收到服務端回復的 ACK,此時從客戶端到服務器的連接已釋放(但服務端到客戶端的連接還未釋放,并且客戶端還可以接收數(shù)據(jù));

  4. 服務端繼續(xù)發(fā)送之前沒發(fā)完的數(shù)據(jù)給客戶端;

  5. 服務端發(fā)送 FIN ACK 給客戶端,說明服務端發(fā)送完了數(shù)據(jù)(請求釋放從服務端到客戶端的連接,就算沒收到客戶端的回復,過段時間也會自動釋放);

  6. 客戶端收到服務端的 FIN ACK,并回復 ACK 給客戶端(同意釋放從服務端到客戶端的連接);

  7. 服務端收到客戶端的 ACK 后,釋放從服務端到客戶端的連接。

TCP 為什么要進行四次揮手?
【問題一】TCP 為什么要進行四次揮手?/ 為什么 TCP 建立連接需要三次,而釋放連接則需要四次?

【答案一】因為 TCP 是全雙工模式,客戶端請求關閉連接后,客戶端向服務端的連接關閉(一二次揮手),服務端繼續(xù)傳輸之前沒傳完的數(shù)據(jù)給客戶端(數(shù)據(jù)傳輸),服務端向客戶端的連接關閉(三四次揮手)。所以 TCP 釋放連接時服務器的 ACK 和 FIN 是分開發(fā)送的(中間隔著數(shù)據(jù)傳輸),而 TCP 建立連接時服務器的 ACK 和 SYN 是一起發(fā)送的(第二次握手),所以 TCP 建立連接需要三次,而釋放連接則需要四次。

【問題二】為什么 TCP 連接時可以 ACK 和 SYN 一起發(fā)送,而釋放時則 ACK 和 FIN 分開發(fā)送呢?(ACK 和 FIN 分開是指第二次和第三次揮手)

【答案二】因為客戶端請求釋放時,服務器可能還有數(shù)據(jù)需要傳輸給客戶端,因此服務端要先響應客戶端 FIN 請求(服務端發(fā)送 ACK),然后數(shù)據(jù)傳輸,傳輸完成后,服務端再提出 FIN 請求(服務端發(fā)送 FIN);而連接時則沒有中間的數(shù)據(jù)傳輸,因此連接時可以 ACK 和 SYN 一起發(fā)送。

【問題三】為什么客戶端釋放最后需要 TIME-WAIT 等待 2MSL 呢?

【答案三】

  1. 為了保證客戶端發(fā)送的最后一個 ACK 報文能夠到達服務端。若未成功到達,則服務端超時重傳 FIN ACK 報文段,客戶端再重傳 ACK,并重新計時。

  1. 防止已失效的連接請求報文段出現(xiàn)在本連接中。TIME-WAIT 持續(xù) 2MSL 可使本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報文段都從網(wǎng)絡中消失,這樣可使下次連接中不會出現(xiàn)舊的連接報文段。



應用層

DNS

  • DNS(Domain Name System,域名系統(tǒng))是互聯(lián)網(wǎng)的一項服務。它作為將域名和 IP 地址相互映射的一個分布式數(shù)據(jù)庫,能夠使人更方便地訪問互聯(lián)網(wǎng)。DNS 使用 TCP 和 UDP 端口 53。當前,對于每一級域名長度的限制是 63 個字符,域名總長度則不能超過 253 個字符。

域名:

  • 域名 ::= {<三級域名>.<二級域名>.<頂級域名>},如:blog.huihut.com

FTP

  • FTP(File Transfer Protocol,文件傳輸協(xié)議)是用于在網(wǎng)絡上進行文件傳輸?shù)囊惶讟藴蕝f(xié)議,使用客戶/服務器模式,使用 TCP 數(shù)據(jù)報,提供交互式訪問,雙向傳輸。

  • TFTP(Trivial File Transfer Protocol,簡單文件傳輸協(xié)議)一個小且易實現(xiàn)的文件傳輸協(xié)議,也使用客戶-服務器方式,使用UDP數(shù)據(jù)報,只支持文件傳輸而不支持交互,沒有列目錄,不能對用戶進行身份鑒定

TELNET

  • TELNET 協(xié)議是 TCP/IP 協(xié)議族中的一員,是 Internet 遠程登陸服務的標準協(xié)議和主要方式。它為用戶提供了在本地計算機上完成遠程主機工作的能力。

  • HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是用于從 WWW(World Wide Web,萬維網(wǎng))服務器傳輸超文本到本地瀏覽器的傳送協(xié)議。

  • SMTP(Simple Mail Transfer Protocol,簡單郵件傳輸協(xié)議)是一組用于由源地址到目的地址傳送郵件的規(guī)則,由它來控制信件的中轉(zhuǎn)方式。SMTP 協(xié)議屬于 TCP/IP 協(xié)議簇,它幫助每臺計算機在發(fā)送或中轉(zhuǎn)信件時找到下一個目的地。

  • Socket 建立網(wǎng)絡通信連接至少要一對端口號(Socket)。Socket 本質(zhì)是編程接口(API),對 TCP/IP 的封裝,TCP/IP 也要提供可供程序員做網(wǎng)絡開發(fā)所用的接口,這就是 Socket 編程接口。

WWW

  • WWW(World Wide Web,環(huán)球信息網(wǎng),萬維網(wǎng))是一個由許多互相鏈接的超文本組成的系統(tǒng),通過互聯(lián)網(wǎng)訪問

URL
  • URL(Uniform Resource Locator,統(tǒng)一資源定位符)是因特網(wǎng)上標準的資源的地址(Address)

標準格式:

  • 協(xié)議類型:[//服務器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片段ID]

完整格式:

  • 協(xié)議類型:[//[訪問資源需要的憑證信息@]服務器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片段ID]

其中【訪問憑證信息@;:端口號;?查詢;#片段ID】都屬于選填項 ?
如:https://github.com/huihut/interview#cc

HTTP
HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是一種用于分布式、協(xié)作式和超媒體信息系統(tǒng)的應用層協(xié)議。HTTP 是萬維網(wǎng)的數(shù)據(jù)通信的基礎。

請求方法

方法意義
OPTIONS請求一些選項信息,允許客戶端查看服務器的性能
GET請求指定的頁面信息,并返回實體主體
HEAD類似于 get 請求,只不過返回的響應中沒有具體的內(nèi)容,用于獲取報頭
POST向指定資源提交數(shù)據(jù)進行處理請求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改
PUT從客戶端向服務器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容
DELETE請求服務器刪除指定的頁面
TRACE回顯服務器收到的請求,主要用于測試或診斷
狀態(tài)碼(Status-Code)

  • 1xx:表示通知信息,如請求收到了或正在進行處理

    • 100 Continue:繼續(xù),客戶端應繼續(xù)其請求

    • 101 Switching Protocols 切換協(xié)議。服務器根據(jù)客戶端的請求切換協(xié)議。只能切換到更高級的協(xié)議,例如,切換到 HTTP 的新版本協(xié)議

  • 2xx:表示成功,如接收或知道了

    • 200 OK: 請求成功

  • 3xx:表示重定向,如要完成請求還必須采取進一步的行動

    • 301 Moved Permanently: 永久移動。請求的資源已被永久的移動到新 URL,返回信息會包括新的 URL,瀏覽器會自動定向到新 URL。今后任何新的請求都應使用新的 URL 代替

  • 4xx:表示客戶的差錯,如請求中有錯誤的語法或不能完成

    • 400 Bad Request: 客戶端請求的語法錯誤,服務器無法理解

    • 401 Unauthorized: 請求要求用戶的身份認證

    • 403 Forbidden: 服務器理解請求客戶端的請求,但是拒絕執(zhí)行此請求(權限不夠)

    • 404 Not Found: 服務器無法根據(jù)客戶端的請求找到資源(網(wǎng)頁)。通過此代碼,網(wǎng)站設計人員可設置 “您所請求的資源無法找到” 的個性頁面

    • 408 Request Timeout: 服務器等待客戶端發(fā)送的請求時間過長,超時

  • 5xx:表示服務器的差錯,如服務器失效無法完成請求

    • 500 Internal Server Error: 服務器內(nèi)部錯誤,無法完成請求

    • 503 Service Unavailable: 由于超載或系統(tǒng)維護,服務器暫時的無法處理客戶端的請求。延時的長度可包含在服務器的 Retry-After 頭信息中

    • 504 Gateway Timeout: 充當網(wǎng)關或代理的服務器,未及時從遠端服務器獲取請求

更多狀態(tài)碼:菜鳥教程 . HTTP狀態(tài)碼

其他協(xié)議
  • SMTP(Simple Main Transfer Protocol,簡單郵件傳輸協(xié)議)是在 Internet 傳輸 Email 的標準,是一個相對簡單的基于文本的協(xié)議。在其之上指定了一條消息的一個或多個接收者(在大多數(shù)情況下被確認是存在的),然后消息文本會被傳輸??梢院芎唵蔚赝ㄟ^ Telnet 程序來測試一個 SMTP 服務器。SMTP 使用 TCP 端口 25。

  • DHCP(Dynamic Host Configuration Protocol,動態(tài)主機設置協(xié)議)是一個局域網(wǎng)的網(wǎng)絡協(xié)議,使用 UDP 協(xié)議工作,主要有兩個用途:

    • 用于內(nèi)部網(wǎng)絡或網(wǎng)絡服務供應商自動分配 IP 地址給用戶

    • 用于內(nèi)部網(wǎng)絡管理員作為對所有電腦作中央管理的手段

  • SNMP(Simple Network Management Protocol,簡單網(wǎng)絡管理協(xié)議)構(gòu)成了互聯(lián)網(wǎng)工程工作小組(IETF,Internet Engineering Task Force)定義的 Internet 協(xié)議族的一部分。該協(xié)議能夠支持網(wǎng)絡管理系統(tǒng),用以監(jiān)測連接到網(wǎng)絡上的設備是否有任何引起管理上關注的情況。

網(wǎng)絡編程

Socket

Socket 中的 read()、write() 函數(shù)

ssize_t?read(int?fd,?void?*buf,?size_t?count);
ssize_t?write(int?fd,?const?void?*buf,?size_t?count);
read()
  • read 函數(shù)是負責從 fd 中讀取內(nèi)容。

  • 當讀成功時,read 返回實際所讀的字節(jié)數(shù)。

  • 如果返回的值是 0 表示已經(jīng)讀到文件的結(jié)束了,小于 0 表示出現(xiàn)了錯誤。

  • 如果錯誤為 EINTR 說明讀是由中斷引起的;如果是 ECONNREST 表示網(wǎng)絡連接出了問題。

write()
  • write 函數(shù)將 buf 中的 nbytes 字節(jié)內(nèi)容寫入文件描述符 fd。

  • 成功時返回寫的字節(jié)數(shù)。失敗時返回 -1,并設置 errno 變量。

  • 在網(wǎng)絡程序中,當我們向套接字文件描述符寫時有倆種可能。

  • (1)write 的返回值大于 0,表示寫了部分或者是全部的數(shù)據(jù)。

  • (2)返回的值小于 0,此時出現(xiàn)了錯誤。

  • 如果錯誤為 EINTR 表示在寫的時候出現(xiàn)了中斷錯誤;如果為 EPIPE 表示網(wǎng)絡連接出現(xiàn)了問題(對方已經(jīng)關閉了連接)。

Socket 中 TCP 的三次握手建立連接

我們知道 TCP 建立連接要進行 “三次握手”,即交換三個分組。大致流程如下:

  1. 客戶端向服務器發(fā)送一個 SYN J

  2. 服務器向客戶端響應一個 SYN K,并對 SYN J 進行確認 ACK J 1

  3. 客戶端再想服務器發(fā)一個確認 ACK K 1

只有就完了三次握手,但是這個三次握手發(fā)生在 Socket 的那幾個函數(shù)中呢?請看下圖:

socket 中發(fā)送的 TCP 三次握手
從圖中可以看出:

  1. 當客戶端調(diào)用 connect 時,觸發(fā)了連接請求,向服務器發(fā)送了 SYN J 包,這時 connect 進入阻塞狀態(tài);?

  2. 服務器監(jiān)聽到連接請求,即收到 SYN J 包,調(diào)用 accept 函數(shù)接收請求向客戶端發(fā)送 SYN K ,ACK J 1,這時 accept 進入阻塞狀態(tài);?

  3. 客戶端收到服務器的 SYN K ,ACK J 1 之后,這時 connect 返回,并對 SYN K 進行確認;?

  4. 服務器收到 ACK K 1 時,accept 返回,至此三次握手完畢,連接建立。

Socket 中 TCP 的四次握手釋放連接

上面介紹了 socket 中 TCP 的三次握手建立過程,及其涉及的 socket 函數(shù)?,F(xiàn)在我們介紹 socket 中的四次握手釋放連接的過程,請看下圖:

socket 中發(fā)送的 TCP 四次握手
圖示過程如下:

  1. 某個應用進程首先調(diào)用 close 主動關閉連接,這時 TCP 發(fā)送一個 FIN M;

  2. 另一端接收到 FIN M 之后,執(zhí)行被動關閉,對這個 FIN 進行確認。它的接收也作為文件結(jié)束符傳遞給應用進程,因為 FIN 的接收意味著應用進程在相應的連接上再也接收不到額外數(shù)據(jù);

  3. 一段時間之后,接收到文件結(jié)束符的應用進程調(diào)用 close 關閉它的 socket。這導致它的 TCP 也發(fā)送一個 FIN N;

  4. 接收到這個 FIN 的源發(fā)送端 TCP 對它進行確認。

這樣每個方向上都有一個 FIN 和 ACK。

數(shù)據(jù)庫

  • 數(shù)據(jù)庫事務四大特性:原子性、一致性、分離性、持久性

  • 數(shù)據(jù)庫索引:順序索引、B 樹索引、hash 索引
    MySQL 索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理

  • SQL 約束 (Constraints)

范式

  • 第一范式(1NF):屬性(字段)是最小單位不可再分

  • 第二范式(2NF):滿足 1NF,每個非主屬性完全依賴于主鍵(消除 1NF 非主屬性對碼的部分函數(shù)依賴)

  • 第三范式(3NF):滿足 2NF,任何非主屬性不依賴于其他非主屬性(消除 2NF 主屬性對碼的傳遞函數(shù)依賴)

  • 鮑依斯-科得范式(BCNF):滿足 3NF,任何非主屬性不能對主鍵子集依賴(消除 3NF 主屬性對碼的部分和傳遞函數(shù)依賴)

  • 第四范式(4NF):滿足 3NF,屬性之間不能有非平凡且非函數(shù)依賴的多值依賴(消除 3NF 非平凡且非函數(shù)依賴的多值依賴)

設計模式

各大設計模式例子參考:CSDN專欄 . C 設計模式 系列博文

設計模式工程目錄

單例模式

單例模式例子

抽象工廠模式

抽象工廠模式例子

適配器模式

適配器模式例子

橋接模式

橋接模式例子

觀察者模式

觀察者模式例子

設計模式的六大原則

  • 單一職責原則(SRP,Single Responsibility Principle)

  • 里氏替換原則(LSP,Liskov Substitution Principle)

  • 依賴倒置原則(DIP,Dependence Inversion Principle)

  • 接口隔離原則(ISP,Interface Segregation Principle)

  • 迪米特法則(LoD,Law of Demeter)

  • 開放封閉原則(OCP,Open Close Principle)

鏈接裝載庫

內(nèi)存、棧、堆

一般應用程序內(nèi)存空間有如下區(qū)域:

  • 棧:由操作系統(tǒng)自動分配釋放,存放函數(shù)的參數(shù)值、局部變量等的值,用于維護函數(shù)調(diào)用的上下文

  • 堆:一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由操作系統(tǒng)回收,用來容納應用程序動態(tài)分配的內(nèi)存區(qū)域

  • 可執(zhí)行文件映像:存儲著可執(zhí)行文件在內(nèi)存中的映像,由裝載器裝載是將可執(zhí)行文件的內(nèi)存讀取或映射到這里

  • 保留區(qū):保留區(qū)并不是一個單一的內(nèi)存區(qū)域,而是對內(nèi)存中受到保護而禁止訪問的內(nèi)存區(qū)域的總稱,如通常 C 語言講無效指針賦值為 0(NULL),因此 0 地址正常情況下不可能有效的訪問數(shù)據(jù)

棧保存了一個函數(shù)調(diào)用所需要的維護信息,常被稱為堆棧幀(Stack Frame)或活動記錄(Activate Record),一般包含以下幾方面:

  • 函數(shù)的返回地址和參數(shù)

  • 臨時變量:包括函數(shù)的非靜態(tài)局部變量以及編譯器自動生成的其他臨時變量

  • 保存上下文:包括函數(shù)調(diào)用前后需要保持不變的寄存器

堆分配算法:

  • 空閑鏈表(Free List)

  • 位圖(Bitmap)

  • 對象池

“段錯誤(segment fault)” 或 “非法操作,該內(nèi)存地址不能 read/write”

典型的非法指針解引用造成的錯誤。當指針指向一個不允許讀寫的內(nèi)存地址,而程序卻試圖利用指針來讀或?qū)懺摰刂窌r,會出現(xiàn)這個錯誤。

普遍原因:

  • 將指針初始化為 NULL,之后沒有給它一個合理的值就開始使用指針

  • 沒用初始化棧中的指針,指針的值一般會是隨機數(shù),之后就直接開始使用指針

編譯鏈接

各平臺文件格式

平臺可執(zhí)行文件目標文件動態(tài)庫/共享對象靜態(tài)庫
Windowsexeobjdlllib
Unix/LinuxELF、outosoa
MacMach-Oodylib、tbd、frameworka、framework

編譯鏈接過程

  1. 預編譯(預編譯器處理如 #include、#define 等預編譯指令,生成 .i.ii 文件)

  2. 編譯(編譯器進行詞法分析、語法分析、語義分析、中間代碼生成、目標代碼生成、優(yōu)化,生成 .s 文件)

  3. 匯編(匯編器把匯編碼翻譯成機器碼,生成 .o 文件)

  4. 鏈接(連接器進行地址和空間分配、符號決議、重定位,生成 .out 文件)

現(xiàn)在版本 GCC 把預編譯和編譯合成一步,預編譯編譯程序 cc1、匯編器 as、連接器 ld

MSVC 編譯環(huán)境,編譯器 cl、連接器 link、可執(zhí)行文件查看器 dumpbin

目標文件

編譯器編譯源代碼后生成的文件叫做目標文件。目標文件從結(jié)構(gòu)上講,它是已經(jīng)編譯后的可執(zhí)行文件格式,只是還沒有經(jīng)過鏈接的過程,其中可能有些符號或有些地址還沒有被調(diào)整。

可執(zhí)行文件(Windows 的 .exe 和 Linux 的 ELF)、動態(tài)鏈接庫(Windows 的 .dll 和 Linux 的 .so)、靜態(tài)鏈接庫(Windows 的 .lib 和 Linux 的 .a)都是按照可執(zhí)行文件格式存儲(Windows 按照 PE-COFF,Linux 按照 ELF)

目標文件格式
  • Windows 的 PE(Portable Executable),或稱為 PE-COFF,.obj 格式

  • Linux 的 ELF(Executable Linkable Format),.o 格式

  • Intel/Microsoft 的 OMF(Object Module Format)

  • Unix 的 a.out 格式

  • MS-DOS 的 .COM 格式

PE 和 ELF 都是 COFF(Common File Format)的變種

目標文件存儲結(jié)構(gòu)
功能
File Header文件頭,描述整個文件的文件屬性(包括文件是否可執(zhí)行、是靜態(tài)鏈接或動態(tài)連接及入口地址、目標硬件、目標操作系統(tǒng)等)
.text section代碼段,執(zhí)行語句編譯成的機器代碼
.data section數(shù)據(jù)段,已初始化的全局變量和局部靜態(tài)變量
.bss sectionBSS 段(Block Started by Symbol),未初始化的全局變量和局部靜態(tài)變量(因為默認值為 0,所以只是在此預留位置,不占空間)
.rodata section只讀數(shù)據(jù)段,存放只讀數(shù)據(jù),一般是程序里面的只讀變量(如 const 修飾的變量)和字符串常量
.comment section注釋信息段,存放編譯器版本信息
.note.GNU-stack section堆棧提示段

其他段略

鏈接的接口————符號

在鏈接中,目標文件之間相互拼合實際上是目標文件之間對地址的引用,即對函數(shù)和變量的地址的引用。我們將函數(shù)和變量統(tǒng)稱為符號(Symbol),函數(shù)名或變量名就是符號名(Symbol Name)。

如下符號表(Symbol Table):

Symbol(符號名)Symbol Value (地址)
main0x100
Add0x123
......

Linux 的共享庫(Shared Library)

Linux 下的共享庫就是普通的 ELF 共享對象。

共享庫版本更新應該保證二進制接口 ABI(Application Binary Interface)的兼容

命名

libname.so.x.y.z

  • x:主版本號,不同主版本號的庫之間不兼容,需要重新編譯

  • y:次版本號,高版本號向后兼容低版本號

  • z:發(fā)布版本號,不對接口進行更改,完全兼容

路徑

大部分包括 Linux 在內(nèi)的開源系統(tǒng)遵循 FHS(File Hierarchy Standard)的標準,這標準規(guī)定了系統(tǒng)文件如何存放,包括各個目錄結(jié)構(gòu)、組織和作用。

  • /lib:存放系統(tǒng)最關鍵和最基礎的共享庫,如動態(tài)鏈接器、C 語言運行庫、數(shù)學庫等

  • /usr/lib:存放非系統(tǒng)運行時所需要的關鍵性的庫,主要是開發(fā)庫

  • /usr/local/lib:存放跟操作系統(tǒng)本身并不十分相關的庫,主要是一些第三方應用程序的庫

動態(tài)鏈接器會在 /lib、/usr/lib 和由 /etc/ld.so.conf 配置文件指定的,目錄中查找共享庫

環(huán)境變量

  • LD_LIBRARY_PATH:臨時改變某個應用程序的共享庫查找路徑,而不會影響其他應用程序

  • LD_PRELOAD:指定預先裝載的一些共享庫甚至是目標文件

  • LD_DEBUG:打開動態(tài)鏈接器的調(diào)試功能

so 共享庫的編寫

使用 CLion 編寫共享庫

創(chuàng)建一個名為 MySharedLib 的共享庫

CMakeLists.txt

cmake_minimum_required(VERSION?3.10)
project(MySharedLib)

set(CMAKE_CXX_STANDARD?11)

add_library(MySharedLib?SHARED?library.cpp?library.h)
library.h

#ifndef?MYSHAREDLIB_LIBRARY_H
#define?MYSHAREDLIB_LIBRARY_H

//?打印?Hello?World!
void?hello();

//?使用可變模版參數(shù)求和
template?<typename?T>
T?sum(T?t)
{
????return?t;
}
template?<typename?T,?typename?...Types>
T?sum(T?first,?Types?...?rest)
{
????return?first? ?sum(rest...);
}

#endif
library.cpp

#include?
#include?"library.h"

void?hello()?{
????std::cout?<"Hello,?World!"?<std::endl;
}

so 共享庫的使用(被可執(zhí)行項目調(diào)用)

使用 CLion 調(diào)用共享庫

創(chuàng)建一個名為 TestSharedLib 的可執(zhí)行項目

CMakeLists.txt

cmake_minimum_required(VERSION?3.10)
project(TestSharedLib)

#?C 11?編譯
set(CMAKE_CXX_STANDARD?11)

#?頭文件路徑
set(INC_DIR?/home/xx/code/clion/MySharedLib)
#?庫文件路徑
set(LIB_DIR?/home/xx/code/clion/MySharedLib/cmake-build-debug)

include_directories(${INC_DIR})
link_directories(${LIB_DIR})
link_libraries(MySharedLib)

add_executable(TestSharedLib?main.cpp)

#?鏈接?MySharedLib?庫
target_link_libraries(TestSharedLib?MySharedLib)
main.cpp

#include?
#include?"library.h"
using?std::cout;
using?std::endl;

int?main()?{

????hello();
????cout?<"1? ?2?=?"?<1,2)?<endl;
????cout?<"1? ?2? ?3?=?"?<1,2,3)?<endl;

????return?0;
}
執(zhí)行結(jié)果

Hello,?World!
1? ?2?=?3
1? ?2? ?3?=?6

Windows 應用程序入口函數(shù)

  • GUI(Graphical User Interface)應用,鏈接器選項:/SUBSYSTEM:WINDOWS

  • CUI(Console User Interface)應用,鏈接器選項:/SUBSYSTEM:CONSOLE

_tWinMain 與 _tmain 函數(shù)聲明

Int?WINAPI?_tWinMain(
????HINSTANCE?hInstanceExe,
????HINSTANCE,
????PTSTR?pszCmdLine,
????int?nCmdShow);

int?_tmain(
????int?argc,
????TCHAR?*argv[],
????TCHAR?*envp[]);


應用程序類型入口點函數(shù)嵌入可執(zhí)行文件的啟動函數(shù)
處理ANSI字符(串)的GUI應用程序_tWinMain(WinMain)WinMainCRTSartup
處理Unicode字符(串)的GUI應用程序_tWinMain(wWinMain)wWinMainCRTSartup
處理ANSI字符(串)的CUI應用程序_tmain(Main)mainCRTSartup
處理Unicode字符(串)的CUI應用程序_tmain(wMain)wmainCRTSartup
動態(tài)鏈接庫(Dynamic-Link Library)DllMain_DllMainCRTStartup

Windows 的動態(tài)鏈接庫(Dynamic-Link Library)

知識點來自《Windows核心編程(第五版)》

用處

  • 擴展了應用程序的特性

  • 簡化了項目管理

  • 有助于節(jié)省內(nèi)存

  • 促進了資源的共享

  • 促進了本地化

  • 有助于解決平臺間的差異

  • 可以用于特殊目的

注意

  • 創(chuàng)建 DLL,事實上是在創(chuàng)建可供一個可執(zhí)行模塊調(diào)用的函數(shù)

  • 當一個模塊提供一個內(nèi)存分配函數(shù)(malloc、new)的時候,它必須同時提供另一個內(nèi)存釋放函數(shù)(free、delete)

  • 在使用 C 和 C 混編的時候,要使用 extern "C" 修飾符

  • 一個 DLL 可以導出函數(shù)、變量(避免導出)、C 類(導出導入需要同編譯器,否則避免導出)

  • DLL 模塊:cpp 文件中的 __declspec(dllexport) 寫在 include 頭文件之前

  • 調(diào)用 DLL 的可執(zhí)行模塊:cpp 文件的 __declspec(dllimport) 之前不應該定義 MYLIBAPI

加載 Windows 程序的搜索順序

  1. 包含可執(zhí)行文件的目錄

  2. Windows 的系統(tǒng)目錄,可以通過 GetSystemDirectory 得到

  3. 16 位的系統(tǒng)目錄,即 Windows 目錄中的 System 子目錄

  4. Windows 目錄,可以通過 GetWindowsDirectory 得到

  5. 進程的當前目錄

  6. PATH 環(huán)境變量中所列出的目錄

DLL 入口函數(shù)

DllMain 函數(shù)

BOOL?WINAPI?DllMain(HINSTANCE?hinstDLL,?DWORD?fdwReason,?LPVOID?lpvReserved)
{
????switch(fdwReason)
????{
????case?DLL_PROCESS_ATTACH:
????????//?第一次將一個DLL映射到進程地址空間時調(diào)用
????????//?The?DLL?is?being?mapped?into?the?process'?address?space.
????????break;
????case?DLL_THREAD_ATTACH:
????????//?當進程創(chuàng)建一個線程的時候,用于告訴DLL執(zhí)行與線程相關的初始化(非主線程執(zhí)行)
????????//?A?thread?is?bing?created.
????????break;
????case?DLL_THREAD_DETACH:
????????//?系統(tǒng)調(diào)用?ExitThread?線程退出前,即將終止的線程通過告訴DLL執(zhí)行與線程相關的清理
????????//?A?thread?is?exiting?cleanly.
????????break;
????case?DLL_PROCESS_DETACH:
????????//?將一個DLL從進程的地址空間時調(diào)用
????????//?The?DLL?is?being?unmapped?from?the?process'?address?space.
????????break;
????}
????return?(TRUE);?//?Used?only?for?DLL_PROCESS_ATTACH
}

載入卸載庫

FreeLibraryAndExitThread 函數(shù)聲明

//?載入庫
HMODULE?WINAPI?LoadLibrary(
??_In_?LPCTSTR?lpFileName
)
;
HMODULE?LoadLibraryExA(
??LPCSTR?lpLibFileName,
??HANDLE?hFile,
??DWORD??dwFlags
)
;
//?若要在通用?Windows?平臺(UWP)應用中加載?Win32?DLL,需要調(diào)用?LoadPackagedLibrary,而不是?LoadLibrary?或?LoadLibraryEx
HMODULE?LoadPackagedLibrary(
??LPCWSTR?lpwLibFileName,
??DWORD???Reserved
)
;

//?卸載庫
BOOL?WINAPI?FreeLibrary(
??_In_?HMODULE?hModule
)
;
//?卸載庫和退出線程
VOID?WINAPI?FreeLibraryAndExitThread(
??_In_?HMODULE?hModule,
??_In_?DWORD???dwExitCode
)
;

顯示地鏈接到導出符號

GetProcAddress 函數(shù)聲明

FARPROC?GetProcAddress(
??HMODULE?hInstDll,
??PCSTR?pszSymbolName??//?只能接受?ANSI?字符串,不能是?Unicode
)
;

DumpBin.exe 查看 DLL 信息

VS 的開發(fā)人員命令提示符 使用 DumpBin.exe 可查看 DLL 庫的導出段(導出的變量、函數(shù)、類名的符號)、相對虛擬地址(RVA,relative virtual address)。如:

DUMPBIN?-exports?D:\mydll.dll
DLL 頭文件

//?MyLib.h

#ifdef?MYLIBAPI

//?MYLIBAPI?應該在全部?DLL?源文件的?include?"Mylib.h"?之前被定義
//?全部函數(shù)/變量正在被導出

#else

//?這個頭文件被一個exe源代碼模塊包含,意味著全部函數(shù)/變量被導入
#define?MYLIBAPI?extern?"C"?__declspec(dllimport)

#endif

//?這里定義任何的數(shù)據(jù)結(jié)構(gòu)和符號

//?定義導出的變量(避免導出變量)
MYLIBAPI?int?g_nResult;

//?定義導出函數(shù)原型
MYLIBAPI?int?Add(int?nLeft,?int?nRight);
DLL 源文件

//?MyLibFile1.cpp

//?包含標準Windows和C運行時頭文件
#include?

//?DLL源碼文件導出的函數(shù)和變量
#define?MYLIBAPI?extern?"C"?__declspec(dllexport)

//?包含導出的數(shù)據(jù)結(jié)構(gòu)、符號、函數(shù)、變量
#include?"MyLib.h"

//?將此DLL源代碼文件的代碼放在此處
int?g_nResult;

int?Add(int?nLeft,?int?nRight)
{
????g_nResult?=?nLeft? ?nRight;
????return?g_nResult;
}

DLL 庫的使用(運行時動態(tài)鏈接 DLL)

DLL 庫的使用(運行時動態(tài)鏈接 DLL)

//?A?simple?program?that?uses?LoadLibrary?and?
//?GetProcAddress?to?access?myPuts?from?Myputs.dll.?

#include??
#include??

typedef?int?(__cdecl?*MYPROC)(LPWSTR);?

int?main(?void?)?
{?
????HINSTANCE?hinstLib;?
????MYPROC?ProcAdd;?
????BOOL?fFreeResult,?fRunTimeLinkSuccess?=?FALSE;?

????//?Get?a?handle?to?the?DLL?module.

????hinstLib?=?LoadLibrary(TEXT("MyPuts.dll"));?

????//?If?the?handle?is?valid,?try?to?get?the?function?address.

????if?(hinstLib?!=?NULL)?
????{?
????????ProcAdd?=?(MYPROC)?GetProcAddress(hinstLib,?"myPuts");?

????????//?If?the?function?address?is?valid,?call?the?function.

????????if?(NULL?!=?ProcAdd)?
????????{
????????????fRunTimeLinkSuccess?=?TRUE;
????????????(ProcAdd)?(L"Message?sent?to?the?DLL?function\n");?
????????}
????????//?Free?the?DLL?module.

????????fFreeResult?=?FreeLibrary(hinstLib);?
????}?

????//?If?unable?to?call?the?DLL?function,?use?an?alternative.
????if?(!?fRunTimeLinkSuccess)?
????????printf("Message?printed?from?executable\n");?

????return?0;
}

運行庫(Runtime Library)

典型程序運行步驟

  1. 操作系統(tǒng)創(chuàng)建進程,把控制權交給程序的入口(往往是運行庫中的某個入口函數(shù))

  2. 入口函數(shù)對運行庫和程序運行環(huán)境進行初始化(包括堆、I/O、線程、全局變量構(gòu)造等等)。

  3. 入口函數(shù)初始化后,調(diào)用 main 函數(shù),正式開始執(zhí)行程序主體部分。

  4. main 函數(shù)執(zhí)行完畢后,返回到入口函數(shù)進行清理工作(包括全局變量析構(gòu)、堆銷毀、關閉I/O等),然后進行系統(tǒng)調(diào)用結(jié)束進程。

一個程序的 I/O 指代程序與外界的交互,包括文件、管程、網(wǎng)絡、命令行、信號等。更廣義地講,I/O 指代操作系統(tǒng)理解為 “文件” 的事物。

glibc 入口

_start -> __libc_start_main -> exit -> _exit

其中 main(argc, argv, __environ) 函數(shù)在 __libc_start_main 里執(zhí)行。

MSVC CRT 入口

int mainCRTStartup(void)

執(zhí)行如下操作:

  1. 初始化和 OS 版本有關的全局變量。

  2. 初始化堆。

  3. 初始化 I/O。

  4. 獲取命令行參數(shù)和環(huán)境變量。

  5. 初始化 C 庫的一些數(shù)據(jù)。

  6. 調(diào)用 main 并記錄返回值。

  7. 檢查錯誤并將 main 的返回值返回。

C 語言運行庫(CRT)

大致包含如下功能:

  • 啟動與退出:包括入口函數(shù)及入口函數(shù)所依賴的其他函數(shù)等。

  • 標準函數(shù):有 C 語言標準規(guī)定的C語言標準庫所擁有的函數(shù)實現(xiàn)。

  • I/O:I/O 功能的封裝和實現(xiàn)。

  • 堆:堆的封裝和實現(xiàn)。

  • 語言實現(xiàn):語言中一些特殊功能的實現(xiàn)。

  • 調(diào)試:實現(xiàn)調(diào)試功能的代碼。

C語言標準庫(ANSI C)

包含:

  • 標準輸入輸出(stdio.h)

  • 文件操作(stdio.h)

  • 字符操作(ctype.h)

  • 字符串操作(string.h)

  • 數(shù)學函數(shù)(math.h)

  • 資源管理(stdlib.h)

  • 格式轉(zhuǎn)換(stdlib.h)

  • 時間/日期(time.h)

  • 斷言(assert.h)

  • 各種類型上的常數(shù)(limits.h
本站聲明: 本文章由作者或相關機構(gòu)授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
關閉