重磅干貨:五萬字長文總結(jié)?C/C ?知識(shí)(下)
時(shí)間:2021-08-19 16:12:21
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]↓推薦關(guān)注↓上篇:《重磅干貨|五萬字長文總結(jié)C/C知識(shí)(上)》網(wǎng)絡(luò)層IP(InternetProtocol,網(wǎng)際協(xié)議)是為計(jì)算機(jī)網(wǎng)絡(luò)相互連接進(jìn)行通信而設(shè)計(jì)的協(xié)議。ARP(AddressResolutionProtocol,地址解析協(xié)議)ICMP(InternetControlMe...
↓推薦關(guān)注↓
上篇:《重磅干貨 | 五萬字長文總結(jié) C/C 知識(shí)(上)》
網(wǎng)絡(luò)層
- IP(Internet Protocol,網(wǎng)際協(xié)議)是為計(jì)算機(jī)網(wǎng)絡(luò)相互連接進(jìn)行通信而設(shè)計(jì)的協(xié)議。
- ARP(Address Resolution Protocol,地址解析協(xié)議)
- ICMP(Internet Control Message Protocol,網(wǎng)際控制報(bào)文協(xié)議)
- IGMP(Internet Group Management Protocol,網(wǎng)際組管理協(xié)議)
IP 網(wǎng)際協(xié)議
IP 地址分類:IP 地址 ::= {<網(wǎng)絡(luò)號(hào)>,<主機(jī)號(hào)>}
IP 地址類別 | 網(wǎng)絡(luò)號(hào) | 網(wǎng)絡(luò)范圍 | 主機(jī)號(hào) | IP 地址范圍 |
---|---|---|---|---|
A 類 | 8bit,第一位固定為 0 | 0 —— 127 | 24bit | 1.0.0.0 —— 127.255.255.255 |
B 類 | 16bit,前兩位固定為 10 | 128.0 —— 191.255 | 16bit | 128.0.0.0 —— 191.255.255.255 |
C 類 | 24bit,前三位固定為 110 | 192.0.0 —— 223.255.255 | 8bit | 192.0.0.0 —— 223.255.255.255 |
D 類 | 前四位固定為 1110,后面為多播地址 | |||
E 類 | 前五位固定為 11110,后面保留為今后所用 |
- PING(Packet InterNet Groper,分組網(wǎng)間探測(cè))測(cè)試兩個(gè)主機(jī)之間的連通性
- TTL(Time To Live,生存時(shí)間)該字段指定 IP 包被路由器丟棄之前允許通過的最大網(wǎng)段數(shù)量
內(nèi)部網(wǎng)關(guān)協(xié)議
- RIP(Routing Information Protocol,路由信息協(xié)議)
- OSPF(Open Sortest Path First,開放最短路徑優(yōu)先)
外部網(wǎng)關(guān)協(xié)議
- BGP(Border Gateway Protocol,邊界網(wǎng)關(guān)協(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)絡(luò)地址轉(zhuǎn)換)
路由表包含什么?
- 網(wǎng)絡(luò) ID(Network ID, Network number):就是目標(biāo)地址的網(wǎng)絡(luò) ID。
- 子網(wǎng)掩碼(subnet mask):用來判斷 IP 所屬網(wǎng)絡(luò)
- 下一跳地址/接口(Next hop / interface):就是數(shù)據(jù)在發(fā)送到目標(biāo)地址的旅途中下一站的地址。其中 interface 指向 next hop(即為下一個(gè) route)。一個(gè)自治系統(tǒng)(AS, Autonomous system)中的 route 應(yīng)該包含區(qū)域內(nèi)所有的子網(wǎng)絡(luò),而默認(rèn)網(wǎng)關(guān)(Network id:?
0.0.0.0
, Netmask:?0.0.0.0
)指向自治系統(tǒng)的出口。
- 花費(fèi)(Cost):就是數(shù)據(jù)發(fā)送過程中通過路徑所需要的花費(fèi)。
- 路由的服務(wù)質(zhì)量
- 路由中需要過濾的出/入連接列表
運(yùn)輸層
協(xié)議:- TCP(Transmission Control Protocol,傳輸控制協(xié)議)
- UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)
應(yīng)用程序 | FTP | TELNET | SMTP | DNS | TFTP | HTTP | HTTPS | SNMP |
---|---|---|---|---|---|---|---|---|
端口號(hào) | 21 | 23 | 25 | 53 | 69 | 80 | 443 | 161 |
受限于公眾號(hào)文章字?jǐn)?shù)限制,后續(xù)部分請(qǐng)看【今天的第二篇推文】,
TCP
- TCP(Transmission Control Protocol,傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,其傳輸?shù)膯挝皇菆?bào)文段。
- 面向連接
- 只能點(diǎn)對(duì)點(diǎn)(一對(duì)一)通信
- 可靠交互
- 全雙工通信
- 面向字節(jié)流
- 確認(rèn)和超時(shí)重傳
- 數(shù)據(jù)合理分片和排序
- 流量控制
- 擁塞控制
- 數(shù)據(jù)校驗(yàn)
TCP 首部TCP:狀態(tài)控制碼(Code,Control Flag),占 6 比特,含義如下:
- URG:緊急比特(urgent),當(dāng)
URG=1
時(shí),表明緊急指針字段有效,代表該封包為緊急封包。它告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù),應(yīng)盡快傳送(相當(dāng)于高優(yōu)先級(jí)的數(shù)據(jù)), 且上圖中的 Urgent Pointer 字段也會(huì)被啟用。 - ACK:確認(rèn)比特(Acknowledge)。只有當(dāng)
ACK=1
時(shí)確認(rèn)號(hào)字段才有效,代表這個(gè)封包為確認(rèn)封包。當(dāng)ACK=0
時(shí),確認(rèn)號(hào)無效。 - PSH:(Push function)若為 1 時(shí),代表要求對(duì)方立即傳送緩沖區(qū)內(nèi)的其他對(duì)應(yīng)封包,而無需等緩沖滿了才送。
- RST:復(fù)位比特(Reset),當(dāng)
RST=1
時(shí),表明 TCP 連接中出現(xiàn)嚴(yán)重差錯(cuò)(如由于主機(jī)崩潰或其他原因),必須釋放連接,然后再重新建立運(yùn)輸連接。 - SYN:同步比特(Synchronous),SYN 置為 1,就表示這是一個(gè)連接請(qǐng)求或連接接受報(bào)文,通常帶有 SYN 標(biāo)志的封包表示『主動(dòng)』要連接到對(duì)方的意思。
- FIN:終止比特(Final),用來釋放一個(gè)連接。當(dāng)
FIN=1
時(shí),表明此報(bào)文段的發(fā)送端的數(shù)據(jù)已發(fā)送完畢,并要求釋放運(yùn)輸連接。
UDP
- UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)是 OSI(Open System Interconnection 開放式系統(tǒng)互聯(lián)) 參考模型中一種無連接的傳輸層協(xié)議,提供面向事務(wù)的簡單不可靠信息傳送服務(wù),其傳輸?shù)膯挝皇怯脩魯?shù)據(jù)報(bào)。
- 無連接
- 盡最大努力交付
- 面向報(bào)文
- 沒有擁塞控制
- 支持一對(duì)一、一對(duì)多、多對(duì)一、多對(duì)多的交互通信
- 首部開銷小
TCP 與 UDP 的區(qū)別
- TCP 面向連接,UDP 是無連接的;
- TCP 提供可靠的服務(wù),也就是說,通過 TCP 連接傳送的數(shù)據(jù),無差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP 盡最大努力交付,即不保證可靠交付
- TCP 的邏輯通信信道是全雙工的可靠信道;UDP 則是不可靠信道
- 每一條 TCP 連接只能是點(diǎn)到點(diǎn)的;UDP 支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信
- TCP 面向字節(jié)流(可能出現(xiàn)黏包問題),實(shí)際上是 TCP 把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流;UDP 是面向報(bào)文的(不會(huì)出現(xiàn)黏包問題)
- UDP 沒有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會(huì)使源主機(jī)的發(fā)送速率降低(對(duì)實(shí)時(shí)應(yīng)用很有用,如 IP 電話,實(shí)時(shí)視頻會(huì)議等)
- TCP 首部開銷20字節(jié);UDP 的首部開銷小,只有 8 個(gè)字節(jié)
TCP 黏包問題
原因
TCP 是一個(gè)基于字節(jié)流的傳輸服務(wù)(UDP 基于報(bào)文的),“流” 意味著 TCP 所傳輸?shù)臄?shù)據(jù)是沒有邊界的。所以可能會(huì)出現(xiàn)兩個(gè)數(shù)據(jù)包黏在一起的情況。解決
- 發(fā)送定長包。如果每個(gè)消息的大小都是一樣的,那么在接收對(duì)等方只要累計(jì)接收數(shù)據(jù),直到數(shù)據(jù)等于一個(gè)定長的數(shù)值就將它作為一個(gè)消息。
- 包頭加上包體長度。包頭是定長的 4 個(gè)字節(jié),說明了包體的長度。接收對(duì)等方先接收包頭長度,依據(jù)包頭長度來接收包體。
- 在數(shù)據(jù)包之間設(shè)置邊界,如添加特殊符號(hào)
\r\n
標(biāo)記。FTP 協(xié)議正是這么做的。但問題在于如果數(shù)據(jù)正文中也含有\r\n
,則會(huì)誤判為消息的邊界。 - 使用更加復(fù)雜的應(yīng)用層協(xié)議。
TCP 流量控制
概念
流量控制(flow control)就是讓發(fā)送方的發(fā)送速率不要太快,要讓接收方來得及接收。方法
利用可變窗口進(jìn)行流量控制
TCP 擁塞控制
概念
擁塞控制就是防止過多的數(shù)據(jù)注入到網(wǎng)絡(luò)中,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不致過載。方法
- 慢開始( slow-start )
- 擁塞避免( congestion avoidance )
- 快重傳( fast retransmit )
- 快恢復(fù)( fast recovery?
TCP 傳輸連接管理
因?yàn)?TCP 三次握手建立連接、四次揮手釋放連接很重要,所以附上《計(jì)算機(jī)網(wǎng)絡(luò)(第 7 版)-謝希仁》書中對(duì)此章的詳細(xì)描述:https://github.com/huihut/interview/blob/master/images/TCP-transport-connection-management.png
TCP 三次握手建立連接
- 客戶端發(fā)送 SYN 給服務(wù)器,說明客戶端請(qǐng)求建立連接;
- 服務(wù)端收到客戶端發(fā)的 SYN,并回復(fù) SYN ACK 給客戶端(同意建立連接);
- 客戶端收到服務(wù)端的 SYN ACK 后,回復(fù) ACK 給服務(wù)端(表示客戶端收到了服務(wù)端發(fā)的同意報(bào)文);
- 服務(wù)端收到客戶端的 ACK,連接已建立,可以數(shù)據(jù)傳輸。
TCP 為什么要進(jìn)行三次握手?
【答案一】因?yàn)樾诺啦豢煽浚?TCP 想在不可靠信道上建立可靠地傳輸,那么三次通信是理論上的最小值。(而 UDP 則不需建立可靠傳輸,因此 UDP 不需要三次握手。)Google Groups . TCP 建立連接為什么是三次握手?{技術(shù)}{網(wǎng)絡(luò)通信}【答案二】因?yàn)殡p方都需要確認(rèn)對(duì)方收到了自己發(fā)送的序列號(hào),確認(rèn)過程最少要進(jìn)行三次通信。
知乎 . TCP 為什么是三次握手,而不是兩次或四次?【答案三】為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤。
《計(jì)算機(jī)網(wǎng)絡(luò)(第 7 版)-謝希仁》
【TCP 釋放連接全過程解釋】
- 客戶端發(fā)送 FIN 給服務(wù)器,說明客戶端不必發(fā)送數(shù)據(jù)給服務(wù)器了(請(qǐng)求釋放從客戶端到服務(wù)器的連接);
- 服務(wù)器接收到客戶端發(fā)的 FIN,并回復(fù) ACK 給客戶端(同意釋放從客戶端到服務(wù)器的連接);
- 客戶端收到服務(wù)端回復(fù)的 ACK,此時(shí)從客戶端到服務(wù)器的連接已釋放(但服務(wù)端到客戶端的連接還未釋放,并且客戶端還可以接收數(shù)據(jù));
- 服務(wù)端繼續(xù)發(fā)送之前沒發(fā)完的數(shù)據(jù)給客戶端;
- 服務(wù)端發(fā)送 FIN ACK 給客戶端,說明服務(wù)端發(fā)送完了數(shù)據(jù)(請(qǐng)求釋放從服務(wù)端到客戶端的連接,就算沒收到客戶端的回復(fù),過段時(shí)間也會(huì)自動(dòng)釋放);
- 客戶端收到服務(wù)端的 FIN ACK,并回復(fù) ACK 給客戶端(同意釋放從服務(wù)端到客戶端的連接);
- 服務(wù)端收到客戶端的 ACK 后,釋放從服務(wù)端到客戶端的連接。
TCP 為什么要進(jìn)行四次揮手?
【問題一】TCP 為什么要進(jìn)行四次揮手?/ 為什么 TCP 建立連接需要三次,而釋放連接則需要四次?【答案一】因?yàn)?TCP 是全雙工模式,客戶端請(qǐng)求關(guān)閉連接后,客戶端向服務(wù)端的連接關(guān)閉(一二次揮手),服務(wù)端繼續(xù)傳輸之前沒傳完的數(shù)據(jù)給客戶端(數(shù)據(jù)傳輸),服務(wù)端向客戶端的連接關(guān)閉(三四次揮手)。所以 TCP 釋放連接時(shí)服務(wù)器的 ACK 和 FIN 是分開發(fā)送的(中間隔著數(shù)據(jù)傳輸),而 TCP 建立連接時(shí)服務(wù)器的 ACK 和 SYN 是一起發(fā)送的(第二次握手),所以 TCP 建立連接需要三次,而釋放連接則需要四次。【問題二】為什么 TCP 連接時(shí)可以 ACK 和 SYN 一起發(fā)送,而釋放時(shí)則 ACK 和 FIN 分開發(fā)送呢?(ACK 和 FIN 分開是指第二次和第三次揮手)【答案二】因?yàn)榭蛻舳苏?qǐng)求釋放時(shí),服務(wù)器可能還有數(shù)據(jù)需要傳輸給客戶端,因此服務(wù)端要先響應(yīng)客戶端 FIN 請(qǐng)求(服務(wù)端發(fā)送 ACK),然后數(shù)據(jù)傳輸,傳輸完成后,服務(wù)端再提出 FIN 請(qǐng)求(服務(wù)端發(fā)送 FIN);而連接時(shí)則沒有中間的數(shù)據(jù)傳輸,因此連接時(shí)可以 ACK 和 SYN 一起發(fā)送。【問題三】為什么客戶端釋放最后需要 TIME-WAIT 等待 2MSL 呢?【答案三】- 為了保證客戶端發(fā)送的最后一個(gè) ACK 報(bào)文能夠到達(dá)服務(wù)端。若未成功到達(dá),則服務(wù)端超時(shí)重傳 FIN ACK 報(bào)文段,客戶端再重傳 ACK,并重新計(jì)時(shí)。
- 防止已失效的連接請(qǐng)求報(bào)文段出現(xiàn)在本連接中。TIME-WAIT 持續(xù) 2MSL 可使本連接持續(xù)的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失,這樣可使下次連接中不會(huì)出現(xiàn)舊的連接報(bào)文段。
應(yīng)用層
DNS
- DNS(Domain Name System,域名系統(tǒng))是互聯(lián)網(wǎng)的一項(xiàng)服務(wù)。它作為將域名和 IP 地址相互映射的一個(gè)分布式數(shù)據(jù)庫,能夠使人更方便地訪問互聯(lián)網(wǎng)。DNS 使用 TCP 和 UDP 端口 53。當(dāng)前,對(duì)于每一級(jí)域名長度的限制是 63 個(gè)字符,域名總長度則不能超過 253 個(gè)字符。
域名 ::= {<三級(jí)域名>.<二級(jí)域名>.<頂級(jí)域名>}
,如:blog.huihut.com
FTP
- FTP(File Transfer Protocol,文件傳輸協(xié)議)是用于在網(wǎng)絡(luò)上進(jìn)行文件傳輸?shù)囊惶讟?biāo)準(zhǔn)協(xié)議,使用客戶/服務(wù)器模式,使用 TCP 數(shù)據(jù)報(bào),提供交互式訪問,雙向傳輸。
- TFTP(Trivial File Transfer Protocol,簡單文件傳輸協(xié)議)一個(gè)小且易實(shí)現(xiàn)的文件傳輸協(xié)議,也使用客戶-服務(wù)器方式,使用UDP數(shù)據(jù)報(bào),只支持文件傳輸而不支持交互,沒有列目錄,不能對(duì)用戶進(jìn)行身份鑒定
TELNET
- TELNET 協(xié)議是 TCP/IP 協(xié)議族中的一員,是 Internet 遠(yuǎn)程登陸服務(wù)的標(biāo)準(zhǔn)協(xié)議和主要方式。它為用戶提供了在本地計(jì)算機(jī)上完成遠(yuǎn)程主機(jī)工作的能力。
- HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是用于從 WWW(World Wide Web,萬維網(wǎng))服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。
- SMTP(Simple Mail Transfer Protocol,簡單郵件傳輸協(xié)議)是一組用于由源地址到目的地址傳送郵件的規(guī)則,由它來控制信件的中轉(zhuǎn)方式。SMTP 協(xié)議屬于 TCP/IP 協(xié)議簇,它幫助每臺(tái)計(jì)算機(jī)在發(fā)送或中轉(zhuǎn)信件時(shí)找到下一個(gè)目的地。
- Socket 建立網(wǎng)絡(luò)通信連接至少要一對(duì)端口號(hào)(Socket)。Socket 本質(zhì)是編程接口(API),對(duì) TCP/IP 的封裝,TCP/IP 也要提供可供程序員做網(wǎng)絡(luò)開發(fā)所用的接口,這就是 Socket 編程接口。
WWW
- WWW(World Wide Web,環(huán)球信息網(wǎng),萬維網(wǎng))是一個(gè)由許多互相鏈接的超文本組成的系統(tǒng),通過互聯(lián)網(wǎng)訪問
URL
- URL(Uniform Resource Locator,統(tǒng)一資源定位符)是因特網(wǎng)上標(biāo)準(zhǔn)的資源的地址(Address)
協(xié)議類型:[//服務(wù)器地址[:端口號(hào)]][/資源層級(jí)UNIX文件路徑]文件名[?查詢][#片段ID]
協(xié)議類型:[//[訪問資源需要的憑證信息@]服務(wù)器地址[:端口號(hào)]][/資源層級(jí)UNIX文件路徑]文件名[?查詢][#片段ID]
其中【訪問憑證信息@;:端口號(hào);?查詢;#片段ID】都屬于選填項(xiàng) ?
如:https://github.com/huihut/interview#cc
HTTP
HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是一種用于分布式、協(xié)作式和超媒體信息系統(tǒng)的應(yīng)用層協(xié)議。HTTP 是萬維網(wǎng)的數(shù)據(jù)通信的基礎(chǔ)。請(qǐng)求方法方法 | 意義 |
---|---|
OPTIONS | 請(qǐng)求一些選項(xiàng)信息,允許客戶端查看服務(wù)器的性能 |
GET | 請(qǐng)求指定的頁面信息,并返回實(shí)體主體 |
HEAD | 類似于 get 請(qǐng)求,只不過返回的響應(yīng)中沒有具體的內(nèi)容,用于獲取報(bào)頭 |
POST | 向指定資源提交數(shù)據(jù)進(jìn)行處理請(qǐng)求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請(qǐng)求體中。POST請(qǐng)求可能會(huì)導(dǎo)致新的資源的建立和/或已有資源的修改 |
PUT | 從客戶端向服務(wù)器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容 |
DELETE | 請(qǐng)求服務(wù)器刪除指定的頁面 |
TRACE | 回顯服務(wù)器收到的請(qǐng)求,主要用于測(cè)試或診斷 |
- 1xx:表示通知信息,如請(qǐng)求收到了或正在進(jìn)行處理
- 100 Continue:繼續(xù),客戶端應(yīng)繼續(xù)其請(qǐng)求
- 101 Switching Protocols 切換協(xié)議。服務(wù)器根據(jù)客戶端的請(qǐng)求切換協(xié)議。只能切換到更高級(jí)的協(xié)議,例如,切換到 HTTP 的新版本協(xié)議
- 2xx:表示成功,如接收或知道了
- 200 OK: 請(qǐng)求成功
- 3xx:表示重定向,如要完成請(qǐng)求還必須采取進(jìn)一步的行動(dòng)
- 301 Moved Permanently: 永久移動(dòng)。請(qǐng)求的資源已被永久的移動(dòng)到新 URL,返回信息會(huì)包括新的 URL,瀏覽器會(huì)自動(dòng)定向到新 URL。今后任何新的請(qǐng)求都應(yīng)使用新的 URL 代替
- 4xx:表示客戶的差錯(cuò),如請(qǐng)求中有錯(cuò)誤的語法或不能完成
- 400 Bad Request: 客戶端請(qǐng)求的語法錯(cuò)誤,服務(wù)器無法理解
- 401 Unauthorized: 請(qǐng)求要求用戶的身份認(rèn)證
- 403 Forbidden: 服務(wù)器理解請(qǐng)求客戶端的請(qǐng)求,但是拒絕執(zhí)行此請(qǐng)求(權(quán)限不夠)
- 404 Not Found: 服務(wù)器無法根據(jù)客戶端的請(qǐng)求找到資源(網(wǎng)頁)。通過此代碼,網(wǎng)站設(shè)計(jì)人員可設(shè)置 “您所請(qǐng)求的資源無法找到” 的個(gè)性頁面
- 408 Request Timeout: 服務(wù)器等待客戶端發(fā)送的請(qǐng)求時(shí)間過長,超時(shí)
- 5xx:表示服務(wù)器的差錯(cuò),如服務(wù)器失效無法完成請(qǐng)求
- 500 Internal Server Error: 服務(wù)器內(nèi)部錯(cuò)誤,無法完成請(qǐng)求
- 503 Service Unavailable: 由于超載或系統(tǒng)維護(hù),服務(wù)器暫時(shí)的無法處理客戶端的請(qǐng)求。延時(shí)的長度可包含在服務(wù)器的 Retry-After 頭信息中
- 504 Gateway Timeout: 充當(dāng)網(wǎng)關(guān)或代理的服務(wù)器,未及時(shí)從遠(yuǎn)端服務(wù)器獲取請(qǐng)求
更多狀態(tài)碼:菜鳥教程 . HTTP狀態(tài)碼
其他協(xié)議
- SMTP(Simple Main Transfer Protocol,簡單郵件傳輸協(xié)議)是在 Internet 傳輸 Email 的標(biāo)準(zhǔn),是一個(gè)相對(duì)簡單的基于文本的協(xié)議。在其之上指定了一條消息的一個(gè)或多個(gè)接收者(在大多數(shù)情況下被確認(rèn)是存在的),然后消息文本會(huì)被傳輸。可以很簡單地通過 Telnet 程序來測(cè)試一個(gè) SMTP 服務(wù)器。SMTP 使用 TCP 端口 25。
- DHCP(Dynamic Host Configuration Protocol,動(dòng)態(tài)主機(jī)設(shè)置協(xié)議)是一個(gè)局域網(wǎng)的網(wǎng)絡(luò)協(xié)議,使用 UDP 協(xié)議工作,主要有兩個(gè)用途:
- 用于內(nèi)部網(wǎng)絡(luò)或網(wǎng)絡(luò)服務(wù)供應(yīng)商自動(dòng)分配 IP 地址給用戶
- 用于內(nèi)部網(wǎng)絡(luò)管理員作為對(duì)所有電腦作中央管理的手段
- SNMP(Simple Network Management Protocol,簡單網(wǎng)絡(luò)管理協(xié)議)構(gòu)成了互聯(lián)網(wǎng)工程工作小組(IETF,Internet Engineering Task Force)定義的 Internet 協(xié)議族的一部分。該協(xié)議能夠支持網(wǎng)絡(luò)管理系統(tǒng),用以監(jiān)測(cè)連接到網(wǎng)絡(luò)上的設(shè)備是否有任何引起管理上關(guān)注的情況。
網(wǎng)絡(luò)編程
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ù)是負(fù)責(zé)從 fd 中讀取內(nèi)容。
- 當(dāng)讀成功時(shí),read 返回實(shí)際所讀的字節(jié)數(shù)。
- 如果返回的值是 0 表示已經(jīng)讀到文件的結(jié)束了,小于 0 表示出現(xiàn)了錯(cuò)誤。
- 如果錯(cuò)誤為 EINTR 說明讀是由中斷引起的;如果是 ECONNREST 表示網(wǎng)絡(luò)連接出了問題。
write()
- write 函數(shù)將 buf 中的 nbytes 字節(jié)內(nèi)容寫入文件描述符 fd。
- 成功時(shí)返回寫的字節(jié)數(shù)。失敗時(shí)返回 -1,并設(shè)置 errno 變量。
- 在網(wǎng)絡(luò)程序中,當(dāng)我們向套接字文件描述符寫時(shí)有倆種可能。
- (1)write 的返回值大于 0,表示寫了部分或者是全部的數(shù)據(jù)。
- (2)返回的值小于 0,此時(shí)出現(xiàn)了錯(cuò)誤。
- 如果錯(cuò)誤為 EINTR 表示在寫的時(shí)候出現(xiàn)了中斷錯(cuò)誤;如果為 EPIPE 表示網(wǎng)絡(luò)連接出現(xiàn)了問題(對(duì)方已經(jīng)關(guān)閉了連接)。
Socket 中 TCP 的三次握手建立連接
我們知道 TCP 建立連接要進(jìn)行 “三次握手”,即交換三個(gè)分組。大致流程如下:- 客戶端向服務(wù)器發(fā)送一個(gè) SYN J
- 服務(wù)器向客戶端響應(yīng)一個(gè) SYN K,并對(duì) SYN J 進(jìn)行確認(rèn) ACK J 1
- 客戶端再想服務(wù)器發(fā)一個(gè)確認(rèn) ACK K 1
- 當(dāng)客戶端調(diào)用 connect 時(shí),觸發(fā)了連接請(qǐng)求,向服務(wù)器發(fā)送了 SYN J 包,這時(shí) connect 進(jìn)入阻塞狀態(tài);?
- 服務(wù)器監(jiān)聽到連接請(qǐng)求,即收到 SYN J 包,調(diào)用 accept 函數(shù)接收請(qǐng)求向客戶端發(fā)送 SYN K ,ACK J 1,這時(shí) accept 進(jìn)入阻塞狀態(tài);?
- 客戶端收到服務(wù)器的 SYN K ,ACK J 1 之后,這時(shí) connect 返回,并對(duì) SYN K 進(jìn)行確認(rèn);?
- 服務(wù)器收到 ACK K 1 時(shí),accept 返回,至此三次握手完畢,連接建立。
Socket 中 TCP 的四次握手釋放連接
上面介紹了 socket 中 TCP 的三次握手建立過程,及其涉及的 socket 函數(shù)?,F(xiàn)在我們介紹 socket 中的四次握手釋放連接的過程,請(qǐng)看下圖:- 某個(gè)應(yīng)用進(jìn)程首先調(diào)用 close 主動(dòng)關(guān)閉連接,這時(shí) TCP 發(fā)送一個(gè) FIN M;
- 另一端接收到 FIN M 之后,執(zhí)行被動(dòng)關(guān)閉,對(duì)這個(gè) FIN 進(jìn)行確認(rèn)。它的接收也作為文件結(jié)束符傳遞給應(yīng)用進(jìn)程,因?yàn)?FIN 的接收意味著應(yīng)用進(jìn)程在相應(yīng)的連接上再也接收不到額外數(shù)據(jù);
- 一段時(shí)間之后,接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用 close 關(guān)閉它的 socket。這導(dǎo)致它的 TCP 也發(fā)送一個(gè) FIN N;
- 接收到這個(gè) FIN 的源發(fā)送端 TCP 對(duì)它進(jìn)行確認(rèn)。
數(shù)據(jù)庫
- 數(shù)據(jù)庫事務(wù)四大特性:原子性、一致性、分離性、持久性
- 數(shù)據(jù)庫索引:順序索引、B 樹索引、hash 索引
MySQL 索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理 - SQL 約束 (Constraints)
范式
- 第一范式(1NF):屬性(字段)是最小單位不可再分
- 第二范式(2NF):滿足 1NF,每個(gè)非主屬性完全依賴于主鍵(消除 1NF 非主屬性對(duì)碼的部分函數(shù)依賴)
- 第三范式(3NF):滿足 2NF,任何非主屬性不依賴于其他非主屬性(消除 2NF 主屬性對(duì)碼的傳遞函數(shù)依賴)
- 鮑依斯-科得范式(BCNF):滿足 3NF,任何非主屬性不能對(duì)主鍵子集依賴(消除 3NF 主屬性對(duì)碼的部分和傳遞函數(shù)依賴)
- 第四范式(4NF):滿足 3NF,屬性之間不能有非平凡且非函數(shù)依賴的多值依賴(消除 3NF 非平凡且非函數(shù)依賴的多值依賴)
設(shè)計(jì)模式
各大設(shè)計(jì)模式例子參考:CSDN專欄 . C 設(shè)計(jì)模式 系列博文設(shè)計(jì)模式工程目錄
單例模式
單例模式例子抽象工廠模式
抽象工廠模式例子適配器模式
適配器模式例子橋接模式
橋接模式例子觀察者模式
觀察者模式例子設(shè)計(jì)模式的六大原則
- 單一職責(zé)原則(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)存、棧、堆
一般應(yīng)用程序內(nèi)存空間有如下區(qū)域:- 棧:由操作系統(tǒng)自動(dòng)分配釋放,存放函數(shù)的參數(shù)值、局部變量等的值,用于維護(hù)函數(shù)調(diào)用的上下文
- 堆:一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)可能由操作系統(tǒng)回收,用來容納應(yīng)用程序動(dòng)態(tài)分配的內(nèi)存區(qū)域
- 可執(zhí)行文件映像:存儲(chǔ)著可執(zhí)行文件在內(nèi)存中的映像,由裝載器裝載是將可執(zhí)行文件的內(nèi)存讀取或映射到這里
- 保留區(qū):保留區(qū)并不是一個(gè)單一的內(nèi)存區(qū)域,而是對(duì)內(nèi)存中受到保護(hù)而禁止訪問的內(nèi)存區(qū)域的總稱,如通常 C 語言講無效指針賦值為 0(NULL),因此 0 地址正常情況下不可能有效的訪問數(shù)據(jù)
棧
棧保存了一個(gè)函數(shù)調(diào)用所需要的維護(hù)信息,常被稱為堆棧幀(Stack Frame)或活動(dòng)記錄(Activate Record),一般包含以下幾方面:- 函數(shù)的返回地址和參數(shù)
- 臨時(shí)變量:包括函數(shù)的非靜態(tài)局部變量以及編譯器自動(dòng)生成的其他臨時(shí)變量
- 保存上下文:包括函數(shù)調(diào)用前后需要保持不變的寄存器
堆
堆分配算法:- 空閑鏈表(Free List)
- 位圖(Bitmap)
- 對(duì)象池
“段錯(cuò)誤(segment fault)” 或 “非法操作,該內(nèi)存地址不能 read/write”
典型的非法指針解引用造成的錯(cuò)誤。當(dāng)指針指向一個(gè)不允許讀寫的內(nèi)存地址,而程序卻試圖利用指針來讀或?qū)懺摰刂窌r(shí),會(huì)出現(xiàn)這個(gè)錯(cuò)誤。普遍原因:- 將指針初始化為 NULL,之后沒有給它一個(gè)合理的值就開始使用指針
- 沒用初始化棧中的指針,指針的值一般會(huì)是隨機(jī)數(shù),之后就直接開始使用指針
編譯鏈接
各平臺(tái)文件格式
平臺(tái) | 可執(zhí)行文件 | 目標(biāo)文件 | 動(dòng)態(tài)庫/共享對(duì)象 | 靜態(tài)庫 |
---|---|---|---|---|
Windows | exe | obj | dll | lib |
Unix/Linux | ELF、out | o | so | a |
Mac | Mach-O | o | dylib、tbd、framework | a、framework |
編譯鏈接過程
- 預(yù)編譯(預(yù)編譯器處理如
#include
、#define
等預(yù)編譯指令,生成.i
或.ii
文件) - 編譯(編譯器進(jìn)行詞法分析、語法分析、語義分析、中間代碼生成、目標(biāo)代碼生成、優(yōu)化,生成
.s
文件) - 匯編(匯編器把匯編碼翻譯成機(jī)器碼,生成
.o
文件) - 鏈接(連接器進(jìn)行地址和空間分配、符號(hào)決議、重定位,生成
.out
文件)
現(xiàn)在版本 GCC 把預(yù)編譯和編譯合成一步,預(yù)編譯編譯程序 cc1、匯編器 as、連接器 ldMSVC 編譯環(huán)境,編譯器 cl、連接器 link、可執(zhí)行文件查看器 dumpbin
目標(biāo)文件
編譯器編譯源代碼后生成的文件叫做目標(biāo)文件。目標(biāo)文件從結(jié)構(gòu)上講,它是已經(jīng)編譯后的可執(zhí)行文件格式,只是還沒有經(jīng)過鏈接的過程,其中可能有些符號(hào)或有些地址還沒有被調(diào)整。可執(zhí)行文件(Windows 的.exe
和 Linux 的ELF
)、動(dòng)態(tài)鏈接庫(Windows 的.dll
和 Linux 的.so
)、靜態(tài)鏈接庫(Windows 的.lib
和 Linux 的.a
)都是按照可執(zhí)行文件格式存儲(chǔ)(Windows 按照 PE-COFF,Linux 按照 ELF)
目標(biāo)文件格式
- 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)的變種
目標(biāo)文件存儲(chǔ)結(jié)構(gòu)
段 | 功能 |
---|---|
File Header | 文件頭,描述整個(gè)文件的文件屬性(包括文件是否可執(zhí)行、是靜態(tài)鏈接或動(dòng)態(tài)連接及入口地址、目標(biāo)硬件、目標(biāo)操作系統(tǒng)等) |
.text section | 代碼段,執(zhí)行語句編譯成的機(jī)器代碼 |
.data section | 數(shù)據(jù)段,已初始化的全局變量和局部靜態(tài)變量 |
.bss section | BSS 段(Block Started by Symbol),未初始化的全局變量和局部靜態(tài)變量(因?yàn)槟J(rèn)值為 0,所以只是在此預(yù)留位置,不占空間) |
.rodata section | 只讀數(shù)據(jù)段,存放只讀數(shù)據(jù),一般是程序里面的只讀變量(如 const 修飾的變量)和字符串常量 |
.comment section | 注釋信息段,存放編譯器版本信息 |
.note.GNU-stack section | 堆棧提示段 |
其他段略
鏈接的接口————符號(hào)
在鏈接中,目標(biāo)文件之間相互拼合實(shí)際上是目標(biāo)文件之間對(duì)地址的引用,即對(duì)函數(shù)和變量的地址的引用。我們將函數(shù)和變量統(tǒng)稱為符號(hào)(Symbol),函數(shù)名或變量名就是符號(hào)名(Symbol Name)。如下符號(hào)表(Symbol Table):Symbol(符號(hào)名) | Symbol Value (地址) |
---|---|
main | 0x100 |
Add | 0x123 |
... | ... |
Linux 的共享庫(Shared Library)
Linux 下的共享庫就是普通的 ELF 共享對(duì)象。共享庫版本更新應(yīng)該保證二進(jìn)制接口 ABI(Application Binary Interface)的兼容命名
libname.so.x.y.z
- x:主版本號(hào),不同主版本號(hào)的庫之間不兼容,需要重新編譯
- y:次版本號(hào),高版本號(hào)向后兼容低版本號(hào)
- z:發(fā)布版本號(hào),不對(duì)接口進(jìn)行更改,完全兼容
路徑
大部分包括 Linux 在內(nèi)的開源系統(tǒng)遵循 FHS(File Hierarchy Standard)的標(biāo)準(zhǔn),這標(biāo)準(zhǔn)規(guī)定了系統(tǒng)文件如何存放,包括各個(gè)目錄結(jié)構(gòu)、組織和作用。/lib
:存放系統(tǒng)最關(guān)鍵和最基礎(chǔ)的共享庫,如動(dòng)態(tài)鏈接器、C 語言運(yùn)行庫、數(shù)學(xué)庫等/usr/lib
:存放非系統(tǒng)運(yùn)行時(shí)所需要的關(guān)鍵性的庫,主要是開發(fā)庫/usr/local/lib
:存放跟操作系統(tǒng)本身并不十分相關(guān)的庫,主要是一些第三方應(yīng)用程序的庫
動(dòng)態(tài)鏈接器會(huì)在/lib
、/usr/lib
和由/etc/ld.so.conf
配置文件指定的,目錄中查找共享庫
環(huán)境變量
LD_LIBRARY_PATH
:臨時(shí)改變某個(gè)應(yīng)用程序的共享庫查找路徑,而不會(huì)影響其他應(yīng)用程序LD_PRELOAD
:指定預(yù)先裝載的一些共享庫甚至是目標(biāo)文件LD_DEBUG
:打開動(dòng)態(tài)鏈接器的調(diào)試功能
so 共享庫的編寫
使用 CLion 編寫共享庫
創(chuàng)建一個(gè)名為 MySharedLib 的共享庫CMakeLists.txtcmake_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í)行項(xiàng)目調(diào)用)
使用 CLion 調(diào)用共享庫
創(chuàng)建一個(gè)名為 TestSharedLib 的可執(zhí)行項(xiàng)目CMakeLists.txtcmake_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 應(yīng)用程序入口函數(shù)
- GUI(Graphical User Interface)應(yīng)用,鏈接器選項(xiàng):
/SUBSYSTEM:WINDOWS
- CUI(Console User Interface)應(yīng)用,鏈接器選項(xiàng):
/SUBSYSTEM:CONSOLE
_tWinMain 與 _tmain 函數(shù)聲明
Int?WINAPI?_tWinMain(
????HINSTANCE?hInstanceExe,
????HINSTANCE,
????PTSTR?pszCmdLine,
????int?nCmdShow);
int?_tmain(
????int?argc,
????TCHAR?*argv[],
????TCHAR?*envp[]);
應(yīng)用程序類型 | 入口點(diǎn)函數(shù) | 嵌入可執(zhí)行文件的啟動(dòng)函數(shù) |
---|---|---|
處理ANSI字符(串)的GUI應(yīng)用程序 | _tWinMain(WinMain) | WinMainCRTSartup |
處理Unicode字符(串)的GUI應(yīng)用程序 | _tWinMain(wWinMain) | wWinMainCRTSartup |
處理ANSI字符(串)的CUI應(yīng)用程序 | _tmain(Main) | mainCRTSartup |
處理Unicode字符(串)的CUI應(yīng)用程序 | _tmain(wMain) | wmainCRTSartup |
動(dòng)態(tài)鏈接庫(Dynamic-Link Library) | DllMain | _DllMainCRTStartup |
Windows 的動(dòng)態(tài)鏈接庫(Dynamic-Link Library)
知識(shí)點(diǎn)來自《Windows核心編程(第五版)》
用處
- 擴(kuò)展了應(yīng)用程序的特性
- 簡化了項(xiàng)目管理
- 有助于節(jié)省內(nèi)存
- 促進(jìn)了資源的共享
- 促進(jìn)了本地化
- 有助于解決平臺(tái)間的差異
- 可以用于特殊目的
注意
- 創(chuàng)建 DLL,事實(shí)上是在創(chuàng)建可供一個(gè)可執(zhí)行模塊調(diào)用的函數(shù)
- 當(dāng)一個(gè)模塊提供一個(gè)內(nèi)存分配函數(shù)(malloc、new)的時(shí)候,它必須同時(shí)提供另一個(gè)內(nèi)存釋放函數(shù)(free、delete)
- 在使用 C 和 C 混編的時(shí)候,要使用 extern "C" 修飾符
- 一個(gè) DLL 可以導(dǎo)出函數(shù)、變量(避免導(dǎo)出)、C 類(導(dǎo)出導(dǎo)入需要同編譯器,否則避免導(dǎo)出)
- DLL 模塊:cpp 文件中的 __declspec(dllexport) 寫在 include 頭文件之前
- 調(diào)用 DLL 的可執(zhí)行模塊:cpp 文件的 __declspec(dllimport) 之前不應(yīng)該定義 MYLIBAPI
加載 Windows 程序的搜索順序
- 包含可執(zhí)行文件的目錄
- Windows 的系統(tǒng)目錄,可以通過 GetSystemDirectory 得到
- 16 位的系統(tǒng)目錄,即 Windows 目錄中的 System 子目錄
- Windows 目錄,可以通過 GetWindowsDirectory 得到
- 進(jìn)程的當(dāng)前目錄
- PATH 環(huán)境變量中所列出的目錄
DLL 入口函數(shù)
DllMain 函數(shù)
BOOL?WINAPI?DllMain(HINSTANCE?hinstDLL,?DWORD?fdwReason,?LPVOID?lpvReserved)
{
????switch(fdwReason)
????{
????case?DLL_PROCESS_ATTACH:
????????//?第一次將一個(gè)DLL映射到進(jìn)程地址空間時(shí)調(diào)用
????????//?The?DLL?is?being?mapped?into?the?process'?address?space.
????????break;
????case?DLL_THREAD_ATTACH:
????????//?當(dāng)進(jìn)程創(chuàng)建一個(gè)線程的時(shí)候,用于告訴DLL執(zhí)行與線程相關(guān)的初始化(非主線程執(zhí)行)
????????//?A?thread?is?bing?created.
????????break;
????case?DLL_THREAD_DETACH:
????????//?系統(tǒng)調(diào)用?ExitThread?線程退出前,即將終止的線程通過告訴DLL執(zhí)行與線程相關(guān)的清理
????????//?A?thread?is?exiting?cleanly.
????????break;
????case?DLL_PROCESS_DETACH:
????????//?將一個(gè)DLL從進(jìn)程的地址空間時(shí)調(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?平臺(tái)(UWP)應(yīng)用中加載?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
);
顯示地鏈接到導(dǎo)出符號(hào)
GetProcAddress 函數(shù)聲明
FARPROC?GetProcAddress(
??HMODULE?hInstDll,
??PCSTR?pszSymbolName??//?只能接受?ANSI?字符串,不能是?Unicode
);
DumpBin.exe 查看 DLL 信息
在VS 的開發(fā)人員命令提示符
使用 DumpBin.exe
可查看 DLL 庫的導(dǎo)出段(導(dǎo)出的變量、函數(shù)、類名的符號(hào))、相對(duì)虛擬地址(RVA,relative virtual address)。如:DUMPBIN?-exports?D:\mydll.dll
DLL 頭文件//?MyLib.h
#ifdef?MYLIBAPI
//?MYLIBAPI?應(yīng)該在全部?DLL?源文件的?include?"Mylib.h"?之前被定義
//?全部函數(shù)/變量正在被導(dǎo)出
#else
//?這個(gè)頭文件被一個(gè)exe源代碼模塊包含,意味著全部函數(shù)/變量被導(dǎo)入
#define?MYLIBAPI?extern?"C"?__declspec(dllimport)
#endif
//?這里定義任何的數(shù)據(jù)結(jié)構(gòu)和符號(hào)
//?定義導(dǎo)出的變量(避免導(dǎo)出變量)
MYLIBAPI?int?g_nResult;
//?定義導(dǎo)出函數(shù)原型
MYLIBAPI?int?Add(int?nLeft,?int?nRight);
DLL 源文件//?MyLibFile1.cpp
//?包含標(biāo)準(zhǔn)Windows和C運(yùn)行時(shí)頭文件
#include?
//?DLL源碼文件導(dǎo)出的函數(shù)和變量
#define?MYLIBAPI?extern?"C"?__declspec(dllexport)
//?包含導(dǎo)出的數(shù)據(jù)結(jié)構(gòu)、符號(hào)、函數(shù)、變量
#include?"MyLib.h"
//?將此DLL源代碼文件的代碼放在此處
int?g_nResult;
int?Add(int?nLeft,?int?nRight)
{
????g_nResult?=?nLeft? ?nRight;
????return?g_nResult;
}
DLL 庫的使用(運(yùn)行時(shí)動(dòng)態(tài)鏈接 DLL)
DLL 庫的使用(運(yùn)行時(shí)動(dòng)態(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;
}
運(yùn)行庫(Runtime Library)
典型程序運(yùn)行步驟
- 操作系統(tǒng)創(chuàng)建進(jìn)程,把控制權(quán)交給程序的入口(往往是運(yùn)行庫中的某個(gè)入口函數(shù))
- 入口函數(shù)對(duì)運(yùn)行庫和程序運(yùn)行環(huán)境進(jìn)行初始化(包括堆、I/O、線程、全局變量構(gòu)造等等)。
- 入口函數(shù)初始化后,調(diào)用 main 函數(shù),正式開始執(zhí)行程序主體部分。
- main 函數(shù)執(zhí)行完畢后,返回到入口函數(shù)進(jìn)行清理工作(包括全局變量析構(gòu)、堆銷毀、關(guān)閉I/O等),然后進(jìn)行系統(tǒng)調(diào)用結(jié)束進(jìn)程。
一個(gè)程序的 I/O 指代程序與外界的交互,包括文件、管程、網(wǎng)絡(luò)、命令行、信號(hào)等。更廣義地講,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í)行如下操作:- 初始化和 OS 版本有關(guān)的全局變量。
- 初始化堆。
- 初始化 I/O。
- 獲取命令行參數(shù)和環(huán)境變量。
- 初始化 C 庫的一些數(shù)據(jù)。
- 調(diào)用 main 并記錄返回值。
- 檢查錯(cuò)誤并將 main 的返回值返回。
C 語言運(yùn)行庫(CRT)
大致包含如下功能:- 啟動(dòng)與退出:包括入口函數(shù)及入口函數(shù)所依賴的其他函數(shù)等。
- 標(biāo)準(zhǔn)函數(shù):有 C 語言標(biāo)準(zhǔn)規(guī)定的C語言標(biāo)準(zhǔn)庫所擁有的函數(shù)實(shí)現(xiàn)。
- I/O:I/O 功能的封裝和實(shí)現(xiàn)。
- 堆:堆的封裝和實(shí)現(xiàn)。
- 語言實(shí)現(xiàn):語言中一些特殊功能的實(shí)現(xiàn)。
- 調(diào)試:實(shí)現(xiàn)調(diào)試功能的代碼。
C語言標(biāo)準(zhǔn)庫(ANSI C)
包含:- 標(biāo)準(zhǔn)輸入輸出(stdio.h)
- 文件操作(stdio.h)
- 字符操作(ctype.h)
- 字符串操作(string.h)
- 數(shù)學(xué)函數(shù)(math.h)
- 資源管理(stdlib.h)
- 格式轉(zhuǎn)換(stdlib.h)
- 時(shí)間/日期(time.h)
- 斷言(assert.h)
- 各種類型上的常數(shù)(limits.h