(1)string類的實現(使用strlen、strcpy、strcat、strcmp等,注意判NULL)。
(2)C++字符串和C字符串的轉換:data()以字符形式返回字符串內容,但不添加’\0\;c_str()返回一個以’\0’結尾的字符數組;copy()把字符串內容複製或寫入既有的c_string或字符數組內。
(3)string和int互轉:snprintf()、strtol/strtoll/strtoull.
(4)經常使用成員函數:capacity()、max_size()、size()、length()、empty()、resize()html
(1)容器大小size()指元素個數,容量capacity()指分配的內存大小
(2)遍歷:for(int i=0;i<a.size();++i
、for(iter=ivector.begin();iter!=ivector.end();iter++)
、for_each
(3)查找find()、刪除erase()/pop_back()、增長insert()/push_front(),注意for 循環遍歷刪除時的坑:for語句條件裏刪除元素時,返回值指向已刪除元素的下一個位置,不是刪除元素時則直接++
(4)reserve()提早設定容量大小;swap()強行釋放vector所佔內存linux
(1)map內部自建一顆紅黑樹,具備對數據自動排序的功能。須回顧二叉樹、紅黑樹。。。
(2)插入pair數據、數組方式插入、數據方式覆蓋插入
(3)遍歷:利用前向迭代器、利用反向迭代器、數組方式
(4)查找find()、刪除erase()、排序less/greater程序員
(1)建立、插入元素、刪除元素、查找元素等。。算法
(1)過程:預處理(prepressing),編譯(compilation),彙編(assembly),連接(linking)
(2)預處理:主要處理那些源代碼文件只可以的以」#」開始的預編譯指令。好比「#include」、「#define」,過濾全部註釋,添加行號,保留#pragma編譯器指令等
(3)編譯:掃描(詞法分析)、語法分析、語義分析、源代碼優化、代碼生成和目標代碼優化
(4)連接:把各個模塊之間相互引用的部分都處理好,使得各個模塊之間可以正確的銜接。
原理:把一些指令對其餘符號地址的引用加以修正。連接過程主要包括了地址和空間分配、符號決議和重定位等
(5)靜態連接庫和動態連接庫編程
1.動態連接庫有利於進程間資源共享;
2.動態連接庫升級容易,用靜態庫則須要從新編譯;
3.許多進程或應用程序可在磁盤上共享動態庫的一個副本,可節省內存和減小交換操做,節省磁盤空間;
4.靜態連接庫在編譯的時候將庫函數裝載到程序中,執行速度更快。api
(6)g++和gcc數組
1.後綴爲.c的,gcc將其看成C程序,而g++看成是C++程序;後綴爲.cpp的,二者都認爲是C++程序;
2.編譯階段,g++會自動調用gcc,二者等價;但由於gcc不能自動和C++程序使用的庫連接,因此一般用g++來完成連接,因此一般直接用g++編譯、連接;
3.extern」C」與gcc/g++並沒有關係。緩存
(1)書寫規則,第一部分爲依賴關係,第二部分爲生成目標的方法:安全
target : prerequisites
<tab>command <tab>command
target也就是一個目標文件,能夠是.o文件,也能夠是執行文件,還能夠是一個標籤(Label)。
prerequisites就是,要生成那個target所須要的文件或是目標。
command也就是make須要執行的命令(任意的Shell命令)。這裏要注意的是在命令前面要加上一個tab鍵,不是空格,是按一個tab鍵按出來的空格。
(2)make clean
用於清除編譯產生的二進制文件,保留源文件:bash
clean:
@echo "cleaning project" -rm main *.o @echo "clean completed"
在rm命令前面加了一個小減號的意思就是,也許某些文件出現問題,但不要管,繼續作後面的事
(3)變量,用$(objects)
的方式來使用
(4)$@
擴展成當前規則的目的文件名;$<
擴展成依靠列表中的第一個依靠文件;$^
擴展成整個依靠列表(除掉重複文件名)
(1)目標文件:源代碼編譯後可是沒有進行連接的那些中間文件,好比win下的.obj文件、linux下的.o文件,與可執行文件的內容以及格式很相似。
目標文件中的內容至少有編譯後的機器指令代碼、數據。還包括鏈接時所須要的一些信息,好比符號表、調試信息、字符串等。通常,目標文件會將這些信息按照不一樣的屬性進行分段(其實就是多個必定長度的區域)。
(2)ELF文件主要由文件頭(ELF header)、代碼段(.text)、數據段(.data)、.bss段、只讀數據段(.rodata)、段表(section table)、符號表(.symtab)、字符串表(.strtab)、重定位表(.rel.text)以下圖所示:
(3)代碼段與數據段分開的緣由:
1.權限分別管理。對進程來講,數據段是可讀寫的,指令段是隻讀的。這樣能夠防止程序指令被改寫。
2.指令區與數據區的分離有助於提升程序的局部性,有助於對CPU緩存命中率的提升。
3.當系統運行多個改程序的副本的時候,他們對應的指令都是同樣的,此時內存只須要保留一份改程序的指令便可。固然,每一個副本進程的數據區域是不同的,他們是進程私有的
(4)閱讀ELF文件的工具readelf;得到二進制文件裏符號的工具nm;減小目標文件大小的工具strip
(1)經過跟蹤系統調用觀察程序在後臺所作的事情
(2)跟蹤信號傳遞
(3)統計系統調用
(1)經常使用調試命令
命令 | 描述 |
---|---|
backtrace(或bt) | 查看各級函數調用及參數 |
finish | 連續運行到當前函數返回爲止,而後停下來等待命令 |
frame(或f) 幀編號 | 選擇棧幀 |
info(或i) locals | 查看當前棧幀局部變量的值 |
list(或l) | 列出源代碼,接着上次的位置往下列,每次列10行 |
list 行號 | 列出從第幾行開始的源代碼 |
list 函數名 | 列出某個函數的源代碼 |
b 行號 | 在第幾行設置斷點 |
b 函數名 | 在函數處設置斷點 |
next(或n) | 執行下一行語句 |
print(或p) | 打印表達式的值,經過表達式能夠修改變量的值或者調用函數 |
quit(或q) | 退出gdb調試環境 |
set var | 修改變量的值 |
start | 開始執行程序,停在main函數第一行語句前面等待命令 |
step(或s) | 執行下一行語句,若是有函數調用則進入到函數中 |
(2)用gdb分析、定位coredump文件
實時顯示系統中各個進程的資源佔用情況
使用參考
列出剛剛那一時刻正在運行的進程快照
參數 | 功能 |
---|---|
a | 顯示全部進程 |
-a | 顯示同一終端下的全部程序 |
-A | 顯示全部進程 |
c | 顯示進程的真實名稱 |
-N | 反向選擇 |
-e | 等於「-A」 |
e | 顯示環境變量 |
f | 顯示程序間的關係 |
-H | 顯示樹狀結構 |
r | 顯示當前終端的進程 |
T | 顯示當前終端的全部程序 |
u | 指定用戶的全部進程 |
-au | 顯示較詳細的資訊 |
-aux | 顯示全部包含其餘使用者的行程 |
-C<命令> | 列出指定命令的情況 |
–lines<行數> | 每頁顯示的行數 |
–width<字符數> | 每頁顯示的字符數 |
–help | 顯示幫助信息 |
–version | 顯示版本顯示 |
(1)Valgrind包括以下工具:
1.Memcheck。這是valgrind應用最普遍的工具,一個重量級的內存檢查器,可以發現開發中絕大多數內存錯誤使用狀況,好比:使用未初始化的內存,使用已經釋放了的內存,內存訪問越界等。這也是本文將重點介紹的部分。
2.Callgrind。它主要用來檢查程序中函數調用過程當中出現的問題。
3.Cachegrind。它主要用來檢查程序中緩存使用出現的問題。
4.Helgrind。它主要用來檢查多線程程序中出現的競爭問題。
5.Massif。它主要用來檢查程序中堆棧使用中出現的問題。
6.Extension。能夠利用core提供的功能,本身編寫特定的內存調試工具
(2)linux下典型C程序內存空間佈局:
(3)堆/棧的區別
1)申請方式: 棧區內存由系統自動分配,函數結束時釋放;堆區內存由程序員本身申請,並指明大小,用戶忘釋放時,會形成內存泄露,不過進程結束時會由系統回收。
2)申請後系統的響應: 只要棧的剩餘空間大於所申請的空間,系統將爲程序提供內存,不然將報異常提示棧溢出;堆區,空閒鏈表,分配與回收機制,會產生碎片問題(外部碎片)–>(固定分區存在內部碎片(分配大於實際),可變分區存在外部碎片(太碎沒法分配))。
3)申請大小的限制:棧是1或者2M,能夠本身改,可是最大不超過8M;堆,看主機是多少位的,若是是32位,就是4G
4)申請效率:棧由系統自動分配,速度較快,程序員沒法控制;堆是由new分配的內存,通常速度較慢,並且容易致使內存碎片,可是用起來方便!
5)存儲內容:棧,函數調用(返回值,各個參數,局部變量(靜態變量不入棧));堆,通常在堆的頭部用一個字節存放堆的大小,堆中的具體內容由程序員安排。
6)存取效率的比較:棧比堆快,Eg :char c[] = /」1234567890/」;char *p =/」1234567890/」;讀取c[1]和p[1],c[1]讀取時直接吧字符串中的元素讀到寄存器cl中,而p[1]先把指針值讀到edx中,再根據edx讀取字符,多一次操做。
7)管理方式不一樣:棧,數據結構中的棧;堆,鏈表
8)生長方向:棧,高到低;堆,低到高
(4)Valgrind安裝/使用
使用參考
(1)OSI七層網絡模型vs五層網絡模型vsTCP/IP四層網絡模型
七層 | 五層 | 四層 |
---|---|---|
應用層 | ||
表示層 | ||
會話層 | 應用層 | 應用層 |
傳輸層 | 運輸層 | 傳輸層 |
網絡層 | 網絡層 | 網間層 |
數據鏈路層 | 數據鏈路層 | 網絡接口 |
物理層 | 物理層 |
(2)TCP頭格式和各字段說明
(3)TCP狀態流轉
(4)TCP超時重傳
重傳超時時間RTO設置,1s、2s、4s、8s、16s符合Karm算法。待研究。
(5)TCP滑動窗口
- 「窗口」對應的是一段能夠被髮送者發送的字節序列,其連續的範圍稱之爲「窗口」;
- 「滑動」則是指這段「容許發送的範圍」是能夠隨着發送的過程而變化的,方式就是按順序「滑動」。
(6)TCP擁塞控制
經常使用方法:
1. 慢開始、擁塞避免
2. 快重傳、快恢復
Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。
SO_REUSEADDR等選項,不太懂。
(1)字節序,顧名思義字節的順序,就是大於一個字節類型的數據在內存中的存放順序,一個字節的數據沒有順序的問題了。
(2)主機字節序就是咱們日常說的大端和小端模式:不一樣的CPU有不一樣的字節序類型,這些字節序是指整數在內存中保存的順序,這個叫作主機序。常見的有兩種:a) Little-Endian就是低位字節排放在內存的低地址端;b) Big-Endian就是高位字節排放在內存的低地址端。
(3)網絡字節序:4個字節的32 bit值如下面的次序傳輸:首先是0~7bit,其次8~15bit,而後16~23bit,最後是24~31bit。這種傳輸次序稱做大端字節序。因爲TCP/IP首部中全部的二進制整數在網絡中傳輸時都要求以這種次序,所以它又稱做網絡字節序。
(4)因此,當兩臺採用不一樣字節序的主機通訊時,在發送數據以前都必須通過字節序的轉換成爲網絡字節序後在進行傳輸。
(1)TCP/IP 網絡數據以流的方式傳輸,數據流是由包組成,如何斷定接收方收到的包是不是一個完整的包就要在發送時對包進行處理,這就是封包技術。封包就是給一段數據加上包頭,這樣一來數據包就分爲包頭和包體兩部份內容了
(2)包頭其實上是個大小固定的結構體,其中有個結構體成員變量表示包體的長度,這是個很重要的變量,其餘的結構體成員可根據須要本身定義.根據包頭長度固定以及包頭中含有包體長度的變量就能正確的拆分出一個完整的數據包
(3)利用底層的緩衝區來進行拆包時,因爲TCP也維護了一個緩衝區,因此能夠利用TCP的緩衝區來緩存發送的數據,這樣一來就不須要爲每個鏈接分配一個緩衝區了.對於利用緩存區來拆包,就是循環不停地接收包頭給出的數據,直到收夠爲止,這就是一個完整的TCP包。
本書中講解了四種網絡IO模型:阻塞IO模型、非阻塞IO模型、多路IO複用模型、異步IO模型。
《Unix網絡編程》一書中提到了五種IO模型,分別是:阻塞IO、非阻塞IO、多路複用IO、信號驅動IO以及異步IO。
待學習!
tcpdump [ -adeflnNOpqStvx ] [ -c 數量 ] [ -F 文件名 ] [ -i 網絡接口 ] [ -r 文件名] [ -s snaplen ]
[ -T 類型 ] [ -w 文件名 ] [表達式 ]
一些使用實例
(1)tcpdump -i eth0 host 192.168.0.250 —–在網口eth0上抓取主機地址爲192.168.0.250的全部數據包。
(2)tcpdump -i eth0 net 192.168.0.0/24 —— 在網口eth0上抓取網絡地址爲192.168.0.0/24的全部數據包
(3)tcpdump -i eth0 port 80 —— 在網口eth0上抓取端口爲80的全部數據包(注意,這裏不區分是源端口仍是目的端口)
固然,咱們也能夠指定源端口或目的端口
(4)tcpdump -i eth0 src port 80 and dst port6100 — 在網口eth0上抓取源端口爲80且目的端口爲6100的數據包,這裏用到了and邏輯運算符,後面再介紹
(5)tcpdump -i eth0 icmp — 在網口eth0上抓取全部icmp協議的數據包
netstat [-a][-e][-n][-o][-p Protocol][-r][-s][Interval]
一些使用實例
(1)netstat -a:列出全部端口(包括未監聽端口)
(2)netstat -at:列出全部tcp端口
(3)netstat -au:列出全部udp端口
(4)netstat -l:只顯示監聽端口
(5)netstat -lt:只列出全部監聽 tcp 端口
(6)netstat -lu:只列出全部監聽 udp 端口
(7)netstat -lx:只列出全部監聽 UNIX 端口
(8)netstat -p:在 netstat 輸出中顯示 PID 和進程名稱
(9)netstat -an:在 netstat 輸出中不顯示主機,端口和用戶名。將會使用數字代替那些名稱。
(10)netstat -c:持續輸出 netstat 信息
lsof(list open files)是一個列出當前系統打開文件的工具。在linux環境下,任何事物都以文件的形式存在,經過文件不只僅能夠訪問常規數據,還能夠訪問網絡鏈接和硬件。因此如傳輸控制協議 (TCP) 和用戶數據報協議 (UDP) 套接字等,系統在後臺都爲該應用程序分配了一個文件描述符,不管這個文件的本質如何,該文件描述符爲應用程序與基礎操做系統之間的交互提供了通用接口。由於應用程序打開文件的描述符列表提供了大量關於這個應用程序自己的信息,所以經過lsof工具可以查看這個列表對系統監測以及排錯將是頗有幫助的。
一些使用實例
(1)lsof -i :6666:查看6666端口如今運行狀況
(2)lsof -a -u root -d txt:查看所屬root用戶進程所打開的文件,文件類型爲.txt
(3)lsof/dev/tty1:監控打開的文件和設備。查看設備/dev/tty1被哪些進程佔用
(4)lsof -c server:監控程序。查看指定程序server打開的文件
(5)lsof -u user_name:監控用戶。查看指定用戶user_name打開的文件
(1)多進程頻繁上下文切換引發的額外開銷可能會嚴重影響系統性能;進程間通訊要求複雜的系統級實現
(2)同一個進程內部的多個線程共享該進程的全部資源;經過線程能夠支持同一個應用程序內部的併發,免去了進程頻繁切換的開銷;併發任務間通訊也更簡單。
(3)多線程在的進程在內存中有多個棧,每一個棧對應一個線程,多個棧之間以必定的空白區域隔開,以備棧的增加,任何一個空白區域被填滿都會致使棧溢出。
(1)線程建立:pthread_create函數
(2)線程退出:執行完成後隱式退出;由線程自己顯示調用pthread_exit 函數退出;被其餘線程用pthread_cancel函數終止
(3)pthread_join用於等待一個線程的結束,也就是主線程中要是加了這段代碼,就會在加代碼的位置卡主,直到這個線程執行完畢才往下走。通常都是pthread_exit在線程內退出,而後返回一個值。這個時候就跳到主線程的pthread_join了(由於一直在等你結束),這個返回值會直接送到pthread_join,實現了主與分線程的通訊。
(4)向線程傳遞參數
(5)得到線程id
(1)屬性值不能直接設置,須使用相關函數進行操做,初始化的函數爲pthread_attr_init,這個函數必須在pthread_create函數以前調用,以後必須用pthread_attr_destroy函數來釋放資源。
(2)屬性對象主要包括:做用域(scope)、棧尺寸(stack size)、棧地址(stack address)、優先級(priority)、分離的狀態(detached state)、調度策略和參數(scheduling policy and parameters)。默認的屬性爲非綁定、非分離、缺省1M的堆棧、與父進程一樣級別的優先級。
(1)互斥鎖。經過加鎖將原先分離的多個指令構成不可分割的一個原子操做
(2)條件變量。條件變量自己不是鎖!但它也能夠形成阻塞。一般與互斥鎖配合使用,給多線程提供一個會合的場所。
(3)讀寫鎖。與互斥量相似,但讀寫鎖容許更高的並行性。其特性爲:寫獨佔,讀共享。
(4)信號量。進化版的互斥鎖(1–>N)。信號量本質上是一個非負的整數計數器,它被用來控制對公共資源的訪問。
(1)可重入函數特色:
1.不在函數內部使用靜態或者全局數據
2.不返回靜態或者全局數據,全部的數據都由函數調用者提供
3.使用本地數據,或者經過製做全局數據的本地拷貝來保護全局數據
4. 若是必須訪問全局數據,使用互斥鎖來保護
5.不調用不可重入函數
(2)不可重入函數特色:
1.函數中使用了靜態變量,不管是全局靜態變量仍是局部靜態變量
2.函數返回靜態變量
3.函數中調用了不可重入函數
4.函數中使用了靜態的數據結構
5.調用了malloc/free函數,由於malloc函數是用全局鏈表來管理堆的
6.調用了標準I/O庫函數,標準I/O庫的不少實現都以不可重入的方式使用全局數據結構。
(3)_REENTRANT宏
在一個多線程程序裏,默認狀況下,只有一個errno變量供全部的線程共享。在一個線程準備獲取剛纔的錯誤代碼時,該變量很容易被另外一個線程中的函數調用所改變。相似的問題還存在於fputs之類的函數中,這些函數一般用一個單獨的全局性區域來緩存輸出數據。
爲解決這個問題,須要使用可重入的例程。可重入代碼能夠被屢次調用而仍然工做正常。編寫的多線程程序,經過定義宏_REENTRANT來告訴編譯器咱們須要可重入功能,這個宏的定義必須出現於程序中的任何#include語句以前。
_REENTRANT爲咱們作三件事情,而且作的很是優雅:
1.它會對部分函數從新定義它們的可安全重入的版本,這些函數名字通常不會發生改變,只是會在函數名後面添加_r字符串,如函數名gethostbyname變成gethostbyname_r。
2.stdio.h中原來以宏的形式實現的一些函數將變成可安全重入函數。
3.在error.h中定義的變量error如今將成爲一個函數調用,它可以以一種安全的多線程方式來獲取真正的errno的值。
(1)進程結構:代碼段、數據段、堆棧段。堆棧段包括進程控制塊PCB
(2)程序轉換成進程步驟:
1.內核將程序讀入內存,爲程序分配內存空間
2.內核爲該進程分配進程標識符(PID)和其餘所需資源
3.內核爲進程保存PID及相應的狀態信息,把進程放到運行隊列中等待執行。程序轉化爲進程後就能夠被操做系統的調度程序調度執行了。
(1)fork()函數建立進程。僅僅被調用一次,卻可以返回兩次,它可能有三種不一樣的返回值:
1.在父進程中,fork返回新建立子進程的進程ID;
2.在子進程中,fork返回0;
3.若是建立出錯,fork返回-1
(2)exit()函數結束進程。
1.exit是函數,帶參數,執行完後把控制權交給系統;return是函數執行完後的返回,執行完後把控制權交給調用函數
2.exit是正常終止進程;abort是異常終止
3.exit()會將緩衝區的數據寫完後再退出;_exit()函數直接退出
(1)孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成爲孤兒進程。孤兒進程將被init進程(進程號爲1)所收養,並由init進程對它們完成狀態收集工做。
(2)殭屍進程:一個進程使用fork建立子進程,若是子進程退出,而父進程並無調用wait或waitpid獲取子進程的狀態信息,那麼子進程的進程描述符仍然保存在系統中。
(1)linux或UNIX在系統引導時會開啓不少服務,這些服務就叫做守護進程。守護進程是脫離終端而且在後臺運行的進程
(2)建立守護進程步驟:
1.建立子進程,父進程退出(使子進程成爲孤兒進程)
2.在子進程中建立新的會話(脫離控制終端)
3.改變當前目錄爲根目錄
4.重設文件權限掩碼
5.關閉文件描述符
6.守護進程的退出
(1)管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程或兄弟進程。
(2)無名管道和有名管道(FIFO)。前者用於父進程和子進程間的通訊,後者用於運行於同一臺機器上的任意兩個進程間的通訊。
消息隊列用於運行於同一臺機器上的進程間通訊,它和管道很類似,是一個在系統內核中用來保存消息的隊列,它在系統內核中是以消息鏈表的形式出現。消息鏈表中節點的結構用msg聲明。
(1)共享內存是運行在同一臺機器上的進程間通訊最快的方式,由於數據不須要在不一樣的進程間複製。一般由一個進程建立一塊共享內存區,其他進程對這塊內存區進行讀寫。
(2)獲得共享內存有兩種方式:映射/dev/mem設備和內存映像文件。前一種方式不給系統帶來額外的開銷,但在現實中並不經常使用,由於它控制存取的將是實際的物理內存,在Linux系統下,這隻有經過限制Linux系統存取的內存才能夠作到,這固然不太實際。經常使用的方式是經過shmXXX函數族來實現利用共享內存進行存儲的。
(3)使用共享內存優勢:方便,函數接口簡單,數據的共享使得進程間的數據不用傳送,而是直接訪問,也加快了效率。不像無名管道同樣要求親緣關係。
(4)使用共享內存缺點:沒有提供同步機制,使得在使用共享內存進行進程間通訊時,每每要藉助其餘的手段來進行進程間的同步工做。
信號量又稱爲信號燈,它是用來協調不一樣進程間的數據對象的,而最主要的應用是前一節的共享內存方式的進程間通訊。本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取情況。
(1)ipcs -a列出本用戶全部相關的ipcs參數 (2)ipcs -q列出進程中的消息隊列 (3)ipcs -s列出全部信號量 (4)ipcs -m列出全部共享內存信息 (5)ipcs -l列出系統的限額 (6)ipcs -t列出最後的訪問時間 (7)ipcs -u列出當前的使用狀況