1 Linux第一天====================================================================================node
2 一.基礎命令linux
3 1.history 查看歷史命令,此終端自安裝至如今的全部。git
4 2.命令解析器:算法
5 1)shell. 針對Unix操做系統shell
6 2)bash. 針對Linux操做系統數據庫
7 3)工做方式: 用戶在終端輸入命令, 命令解析器搜索(經過環境變量中的路徑)對應的路徑,查找同名命令,若是找到了就執行該命令。編程
8ubuntu
9 3.遍歷歷史命令:windows
10 1)從當前位置往上: ctrl+p(方向鍵上也行);設計模式
11 2)從當前位置向下: ctrl+n(方向鍵下也行);
12
13 4.光標移動:
14 1)向前 ctrl+b; 2)向後 ctrl+f; 3)移動到行首 ctrl+a; 4)移動到行首 ctrl+e;
15
16 5.刪除光標位置的字符:
17 1)光標後面的字符(即光標蓋住的那個字符):ctrl+d;
18 2) 光標前面的字符:ctrl+h;
19 3) 刪除光標前面的字符串: ctrl+u;
20 4) 刪除光標後面的字符串:ctrl+k;
21
22 二.Linux目錄結構:
23 1. / 根目錄:根目錄下面的是系統文件,通常別動。
24 2. 終端下面的各類顏色表明不一樣的文件
25 1).白色: 普通文件
26 2)藍色: 目錄
27 3)綠色: 可執行文件
28 4)青色: 連接文件
29 5)紅色: 壓縮文件
30 6)黃色: 設備文件
31 7)灰色: 其餘文件
32
33 3.根目錄下面各文件的內容:
34 1)bin: (binary)二進制文件,存放命令(系統命令,可執行的程序)
35
36 2)etc: 系統或用戶安裝的軟件用到的"配置文件";
37 如:查看用戶:etc/passwd (能夠看到當前系統下的全部用戶)用戶登陸時的用戶名和密碼也在該目錄
38
39 3) lib: Linux操做系統運行時使用的一些基本動態庫(.so)。
40
41 4)media:自動掛載外設,會將外設自動掛載到該目錄下。
42
43 5)mnt: 手動掛載目錄。通常默認掛載到該目錄。
44
45 6)opt: 安裝目錄,通常是空的。
46
47 7)root: 超級用戶的家目錄
48
49 8)sbin: 超級用戶運行時用到的命令(存放的地方)
50 9)usr(user software resource): 用戶軟件資源目錄;(1.當前用戶安裝的一些應用程序,2.一些庫文件(如C 的標準庫))。
51 10)boot: 開機啓動項
52 11) dev: 存放設備文件
53 12)home: Linux操做系統全部用戶的家目錄。
54 13)tmp: 存放臨時文件(每次系統從新啓動,都會清空)
55
56 4.yyx@yyx-virtual-machine:/home$: 字符的意義
57 1)$:表示普通用戶; #:表示超級用戶
58 2)@前的內容: 表示當前用戶名;
59 3)@後的內容,在冒號以前: 表示主機名。
60 4)冒號後的內容: 表示當前所在的目錄。
61
62 5.系統安裝程序後綴
63 ubuntu 系統安裝程序後綴:.deb
64 windows 系統安裝程序後綴:.exe
65 安卓 系統安裝程序後綴:.gdb
66
67 6.Linux 七種文件類型
68 1) d: 目錄
69 2) -: 普通文件
70 3) c: 字符設備
71 4) b: 塊設備
72 5) p: 管道
73 6) s: 套接字(實現局域網的傳輸 sorckt)
74 7) l:符號連接
75
76 在細分爲:
77 d, -, l; (佔用內存空間)
78 僞文件:(不佔用內存空間)
79 c, b, p, s;
80 7.建立文件:
81 1)touch 文件; 文件存在,就會更新文件的日期;
82 文件不存在,就會建立文件。
83
84 8.建立嵌套目錄:
85 mkdir wbq/aa/bb -p;(注意後面的參數-p,能夠加在最後面,也能夠加在緊隨mkdir後面) bb目錄在aa目錄裏,aa在wbq目錄裏。
86 pwd 查看當前用戶所在的目錄。
87
88
89 8.查看文件內容:
90 1)cat+文件名: 文件內容顯示在終端上
91 2)more+ 文件名:只能向下翻。回車向下走一行,空格,顯示下一頁。
92 3)less+ 文件名: 能夠上下翻頁
93 4)head -行數 文件名(從文件頭部數)
94 5)tail -行數 文件名(從文件尾部數)
95
96 9.拷貝文件/目錄
97 cp 存在的文件 新文件(當拷貝文件時,須要有"讀權限").
98 1)若是新文件名不存在,就建立
99 2)若是新文件名存在,就覆蓋源文件(這裏要注意,新文件名通常要寫成不存在的,不然原來的內容就丟了)
100 cp拷貝目錄
101 須要加參數 "-r";
102
103 10.建立軟硬連接
104 1)建立軟鏈接:
105 ln -s 建立軟鏈接的源文件名 軟連接名字
106 1)使用相對路徑建立的軟鏈接,移動連接到不一樣的目錄就不可使用了。
107 2)解決這種問題辦法: 建立絕對路徑的軟鏈接。在原文件名前加上它的絕對路徑。
108 2)建立硬連接:
109 ln 建立硬連接的源文件名 硬連接名字
110 1)硬連接的文件不區分相對和絕對路徑。
111 2)硬連接文件不佔用磁盤空間,一改全改(無論哪一個,至關於程序的靜態變量)
112
113 11.修改文件權限的方法(chmod)
114 1)文字法 (r w x ) chmod 修改對象+(-)權限 文件名
115 u 用戶 g 用戶組 o其餘人 a全部人
116
117 2)數字設定法: chmod 數字 文件名
118 寫權限 對應的數字 2
119 讀權限 對應的數字 4
120 執行權限 對應的數子 1
121
122 12.修改文件全部者(chown)
123 1)修改文件的所屬者: chown 全部者 文件名(要使用超級用戶權限)
124 2)修改文件的所屬組 chown 全部者:所屬組 文件名
125 3)修改文件所屬組(第二種方法): sudo chgrp 所屬組 文件名;
126
127 13.文件的查找和檢索
128 1)根據文件的屬性查找 find
129 1)根據文件名 find 查找的路徑 -name "查找的文件名"
130
131 2)根據文件大小 find 查找的路徑 -size 查找的大小
132 大於:+; 小於:-; 等於:(不用寫)
133 如: find ~ -size +100k -size -100M (查找大於100k小於100M的文件)
134 注意: k 小寫 M大寫
135 "~ 當前用戶的家目錄(或者宿主目錄)"
136
137 3)根據文件類型:find 查找的路徑 -type 文件類型
138
139 2)根據文件內容查找 grep
140 1)grep -r "查找的內容" 查找的路徑(能夠和一些命令搭配):find ./ -type f | grep 01.c; "查找當前目錄下,名字含有01.c的普通文件"
141
142 3)locate 文件名;這個命令更快。直接搜索linux數據庫,有索引,因此很快。
143 可是缺點:若是數據庫沒有更新,會有內容找不到。不關機的狀況下,linux默認天天半夜兩點左右更新。
144
145 14.查看文件或目錄屬性
146 1)查看文件文件的字節數,字數, 行數; wc 文件名 參數
147 2)參數:-c: 文件的字符數
148 -l: 文件的行數(也能夠用來喝一些命令搭配); find ./ -type f | wc -l; "查找當前目錄下,普通文件的個數"。
149 -w: 文件的字節數。
150
151 15.查看指定命令所在的路徑:
152 which 命令;能夠查看該命令所在的文件。(cd命令例外, 它被嵌入在系統中)
153
154 16.軟件的安裝和卸載:
155 1.
156 1)主流安裝(在線):
157 1)sudo apt-get install 軟件名 : 安裝
158 2)主流卸載:
159 1)sudo apt-get remove 軟件名 : 卸載
160 3)更新軟件列表
161 1)sudo apt-get update ; (它的工做原理是:更新軟件的下載地址。)更新完後再從新下載
162 4)清空緩存:
163 1) sudo apt-get clean ; 清空在線安裝後的緩存
164 緩存的路徑:
165
166 2.
167 5)安裝包程序安裝:.deb後綴(安裝包的名字)
168
169 6)安裝包安裝的軟件卸載:
170
171 17. U 盤的掛載和卸載
172 1)掛載: mount 命令
173 1)mount + 設備名 + 掛載的目錄
174 2)獲取U盤設備名:
175 sudo fdisk -l;
176 3)顯示中文:
177 加上參數: -o iocharset utf8
178
179 18: sd 閃盤(U盤)
180 hd 移動硬盤
181 fd 軟盤;
182
183 19.壓縮包管理(Linux):
184 1) 壓縮格式: "(只壓縮不打包)"
185 .gz格式:
186 壓縮: gzip 壓縮的文件;
187 缺點: 1. 壓縮不保留原文件, 2.壓縮的時候不能能打包。 3.不能壓縮目錄
188 解壓縮: gunzip 壓縮包名
189
190 .bz2格式:
191 壓縮: bzip2 壓縮的文件;(若是想保留源文件;加參數 -k; bzip2 壓縮的文件 -k )
192 解壓縮: bunzip2 壓縮包名;
193 缺點: 1.壓縮的時候不能打包, 2.不能壓縮目錄
194
195 2)經常使用的壓縮工具:"(只打包不壓縮)"
196 1)tar:打包。
197 參數:j- (指定的壓縮工具)
198 z- (指定的壓縮工具)
199 c- 建立新的壓縮文件
200 x- 從壓縮文件中釋放文件
201 v- 詳細報告壓縮文件信息
202 f- 指定壓縮文件的名字
203
204 2)壓縮語法:
205 tar 參數 壓縮包名稱 原材料(參數,與壓縮工具配合;zc. jc. )
206 1)zcvf
207 tar zcvf test.tar.gz 須要壓縮的文件
208 2) jcvf
209 tar jcvf test.tar.bz2 須要壓縮的文件
210
211 3)解壓縮:
212 tar 參數 壓縮包名
213 語法:
214 .tar.gz後綴的壓縮文件 tar zxvf test.tar.gz
215 .tar.bz2後綴的壓縮文件 tar jxvf test.tar.bz2
216
217 解壓縮到指定目錄:
218 (參數) -C 指定的目錄(路徑)。
219 tar zxvf test.tar.gz -C 路徑
220 tar jxvf test.tar.bz2 -C 路徑
221
222 3) 非主流的壓縮文件:rar
223 1)安裝軟件: rar (sudo apt-get install rar)
224
225 2)壓縮:
226 1)rar a 壓縮包名 原材料; (壓縮包的名字不須要添加後綴)
227 rar a test 須要壓縮的文件
228 2)-r 參數(壓縮目錄): rar a test 須要壓縮的文件 -r;
229
230 3)解壓縮:rar x 壓縮包名
231 rar x test.rar (知道那個的目錄,可加可不加);
232
233 4)zip
234 1)壓縮:
235 壓縮目錄(加參數 -r);(zip (-r) 壓縮包名 原材料);包名不須要後綴
236 zip test 須要壓縮的文件; zip -r test 須要壓縮的目錄 ;
237 2)解壓縮:
238 unzip 壓縮包名 (-d) 解壓縮的目錄(路徑)
239 unzip test.zip (解壓在當前目錄); unzip test.zip -d 指定的目錄
240
241 4)-的使用時機:
242
243 20.進程管理:
244 1) who 當前登陸操做系統的用戶和終端設備編號
245 2) tty
246 3) PID 進程的ID號。
247 查看整個系統 的運行情況:ps
248 4) ps aux | grep 查找的東西
249 5)
250
251 21.手動殺死進程
252 1)kill -9(SIGKILL) 進程PID;
253 2)查看kill的信號: kill -l;
254
255 22.查看環境變量:env
256 1)環境變量的格式:key = value:value:value:……;
257
258 23.任務管理器: top
259 1)關閉它: q 或者 ctrl +
260
261 24.網絡管理:
262 1)獲取網絡接口的信息:ifconfig
263 2)測試與其餘主機的連通性
264 參數
265
266 3)
267
268 三。用戶管理
269 1.添加用戶:
270 1) sudo adduser
271 2.添加用戶組
272
273 vi etc/passwd; vi etc/group;
274
275 3.切換用戶:su; sudo su;這兩個操做的區別
276 1)普通用戶
277 2)超級用戶
278 4.修改用戶密碼:
279 1.修改普通用戶的密碼
280 sudo passwd 用戶名
281 2.修改超級用戶的密碼
282
283 5.刪除用戶
284 sudo deluser 用戶名
285 6.刪除組:
286
287 7.退出:
288
289 命令:動詞在後面
290 腳本:動詞在前面
291
292 四。經常使用服務器搭建:
293 1.FTP服務器的搭建:
294 1)它是:一款軟件;用戶來上傳和下載文件。
295 2)服務器端:
296 a.安裝軟件:sudo
297 b.服務器端須要設置:
298
299 3)從新啓動服務,使配置生效
300 sudo
301
302 4)客戶端的操做
303 1.實名用戶登陸:
304
305 2.上傳個下載文件(注意:只能操做文件,不能操做目錄)
306
307 1)缺點:
308 1)須要告訴對方服務器密碼;
309 2)用戶能夠在服務器任意目錄切換
310
311 3.匿名用戶登陸:
312 必須指定匿名用戶登陸目錄
313
314 五:lftp客戶端的使用
315 1.只是一個登陸ftp 服務器的客戶端
316 2.使用前先安裝: sudo apt-get install lftp
317 3.登陸ftp服務器
318 1.lftp IP(服務器的IP);
319 2.login --- 匿名用戶登陸
320
321 4.基本操做:
322 基本操做: put, get;(與自帶的ftp功能同樣) 。
323 上傳多個文件: mput 文件名;
324 下載多個文件: mget 文件名
325 下載目錄: mirror 目錄名;
326 上傳目錄: mirror -R 目錄名;
327
328 六: 查看掩碼:命令 umask ;
329 它的做用: 本地的掩碼: 0002;本地建立的目錄權限爲 775; 滿權限爲 777; 能夠看出實際權限 = 滿權限-掩碼
330 本地建立的文件的權限爲 664; 本地的目錄權限 - 文件權限 = 111; 能夠看出:文件默認不會給它執行權限。
331
332 "目錄必須有執行權限才能被打開。"
333 ftp上傳的文件默認權限爲 700; 此時只有 ftp 用戶能夠操做,不合理;須要修改配置文件;anoy_umask=022; 這樣ftp用戶傳輸到服務器的文件權限就爲 755了;
334 目錄權限與掩碼的關係: 目錄權限 = 777 - 掩碼;
335 文件權限與掩碼的關係: 文件權限 = 777 - 掩碼 - 111;
336
337 七:nfs網絡共享服務器的搭建和使用
338 1.nfs ===至關於windows的共享目錄
339 2.服務器端:
340 1.安裝服務器程序:sudo apt-get install nfs-kernel-server;
341 2.建立一個共享目錄:
342 1)設置配置文件: /etc/exports; 添加一個共享的目錄(絕對路徑)和 ip 地址段和(權限);
343 2)權限: ro ----只讀; rw ----讀寫; sync -----數據實時同步
344 例如: /home/yyx/xuexi 192.168.22.*(rw,sync) 這個ip地址爲:容許這個網段的用戶掛載共享路徑。
345 3.重啓服務: sudo service nfs-kernel-server restart;
346
347 3.客戶端:
348 1.經過掛載服務器共享目錄的方式:
349 sudo mount serverIP(服務器的Ip):共享的路徑 掛載的路徑;
350 2.退出方式:
351 與普通掛載同樣。sudo umount 掛載的路徑
352
353 八。ssh服務器的使用:(管理員纔會使用)。
354 1.做用: 遠程登陸程序;
355 2.軟件的安裝: sudo apt-get install openssh-server;
356 3.遠程登錄:
357 ssh 用戶名@IP(要遠程登陸的用戶名和它的IP)
358 4.退出:logout。
359
360 九。超級拷貝
361 scp命令: 安裝軟件:sudo apt-get install openssh-server
362 命令: scp-r (遠程服務器用戶名@IP(遠程):遠程服務器的目錄 拷貝到的本地目錄)
363 scp -r Robin@192.168.28.37:/home/Robin/share ~/test
364
365
366 "——————————————————————————————————————————————————————————————————————————————————————————————————————————————————"
367 FTP 服務器搭建和登陸
368 1.先安裝服務器: 命令: sudo apt-get install vsftpd
369 2.修改配置文件: 命令:sudo vi /etc/vsftpd.conf;
370 3.重啓ftp服務: 命令: sudo service vsftpd restart;
371 4.此時只容許實名用戶登陸和操做,匿名用戶只能登陸。
372 5.匿名用戶登錄設置:建立一個專屬匿名用戶根目錄。
373 1)修改配置文件:添上專屬根目錄
374 2)重啓ftp服務器
375 6.此時就均可以登陸和使用了
376 7.用戶登陸:ftp IP(服務器的IP);
377 1)匿名用戶登陸:用戶名:anonymous; 密碼:不須要
378 8.傳輸數據: put; 下載數據: get;
379 9.弊端:只能操做文件,不能操做目錄。
380 "——————————————————————————————————————————————————————————————————————————————————————————————————————————————————"
381
382 "——————————————————————————————————————————————————————————————————————————————————————————————————————————————————"
383 lftp 客戶端的使用;
384
385 "——————————————————————————————————————————————————————————————————————————————————————————————————————————————————"
386
387 十。 VI 的三種模式:
388 1. 命令模式:
389 h左 j下 k上 l下(左右在兩端,上下在中間);
390 2. 文本模式:
391 3. 末行模式:
392
393 4.一些基本操做:
394 1.光標移動到文件開頭: gg; 光標移動到文件尾部: G;
395 2.光標移動到行首:0; 光標移動到行尾: $;
396 3.行跳轉【如: 13行】: 13G;
397 4.刪除光標後的字:x; 刪除光標前的一個字: X; 刪除一個單詞: dw;
398 5.刪除光標前本行的內容:d0; 刪除光標後本行的內容: D;
399 6.刪除光標所在行: dd; 刪除多行: 行數 + dd;
400 7.撤銷: u; 反撤銷: ctr + r;
401 8.複製:複製當前行:yy; 複製從當前行如下 n 行: n yy;
402 9.粘貼: 從光標所在位置下一行粘貼: p; 從光標當前行位置粘貼: P;
403
404 5.可視模式:
405 命令: v; 進入模式後,能夠有選擇的拷貝和刪除(如只拷貝一行中的某些內容)
406
407 6.查找操做:
408 從光標位置向上查找:?+查找的內容; 從光標位置向下查找:/ + 查找的內容; n ----遍歷操做
409 查光標所在位置的內容: 命令 #;
410 7.替換操做: 單字符替換:命令 r(再輸入本身想輸入的內容。)替換光標後的字符;
411
412 8.建立新行:命令 o:當前光標所在行的下面; 命令 O:相反。
413 刪除光標當前行:S,而後進入文本模式; 刪除光標前一個字符:s,而後進入文本模式;
414
415 9.末行模式下的替換:
416 1)先在命令模式下進行查找操做,而後在末行模式下替換。
417 2):s/查找的內容/替換的內容;
418
419 10.分屏操做:
420 水平分屏:sp+文件名 ; 垂直分屏:vsp+文件名 ; 屏幕切換:ctr + ww;
421
422 11.打日誌: -D, -I; -g; -Wall; -O優化等級
423
424
425 "----------------------------------------------------------------------------------"
426 12.生成靜態庫:
427 1.命名格式:libxxx.a
428 2.製做:
429 1)生成 .o文件;gcc -c .c文件 -I(.c文件中使用的)頭文件所在路徑(本身編寫的頭文件);
430 如:"gcc -c *.c -I ../include;"
431
432 2)將生成的.o文件打包; ar rcs 靜態庫的名字 全部的.o文件
433 例如: "ar rcs libCalc.a *.o;"
434
435 查看打包後的靜態庫: nm 名字;
436 "nm libCalc.a;"
437
438 3.靜態庫的使用:"(-I 後面的路徑能夠加空格(版本高的,可加可不加),能夠不加(版本低的))"
439 1)第一種方法; gcc + 測試.c文件 -o 可執行程序的名稱 -I頭文件的路徑 靜態庫的路徑
440 例如:gcc main.c -o app -I ./include lib/libcacal.a;
441 2)第二種方法: gcc + 測試文件 -o 可執行程序名稱 -I 頭文件的路徑 -L 靜態庫的路徑 -l xxx(靜態庫的名字,掐頭去尾(去掉lib 和 .a));
442 例如:gcc main.c -o app1 -I ./include -
443 L ./lib -l cacal;
444 4.靜態庫的優缺點:
445 優勢: 1)庫被打包到可執行程序中,直接發佈可執行便可使用。2)尋址方便,速度快
446
447 缺點: 1)靜態庫的代碼在編譯時被載入可執行程序,因此靜態庫越大,可執行程序越大(這也致使了它的第一個優勢);
448 2)當靜態庫的改變了,可執行程序也必須從新編譯。
449 3)每一個使用靜態庫的進程都要將庫編譯到可執行文件中再加載到內存中,內存消耗嚴重。
450
451 5.問題1:
452 13.生成動態庫:
453 1.命名格式:libxxx.so
454 2.製做:
455 1)生成與位置無關的 .o; gcc -fPIC -c 編譯的.c文件 -I (.c文件中)頭文件的路徑;
456 例如: gcc -fPIC -c *.c -I ../include;
457
458 2) 打包;gcc -shared -o 生成的動態庫的名字 .o文件;
459 gcc -shared -o libCalc.so *.o ;
460
461 3.動態庫的使用:gcc main.c -o 可執行程序的名字 -I (main.c中頭文件路徑) 動態庫的路徑+動態庫的名字
462 gcc main.c -o app2 -I ../include lib/libCalc.so; "注意:這裏面動態庫的路徑不加-L參數,生成的執行程序運行不起來"
463
464 4. ldd + 可執行程序;
465 查看程序執行時,調用的動態庫。
466
467 5.手動添加動態庫的方法:
468 1)臨時添加:(測試的時候使用;)
469 2)永久添加:(修改家目錄的bashrc文件)
470 3)修改配置文件的方式:修改動態連接器的配置文件
471 更新動態連接器:
472 查看連接器的路徑:sudo ldconfig -v參數。
473
474 6.動態庫加載失敗的緣由:
475 1)解決方案:
476 a. (臨時方案,用於程序測試)使用環境變量: LD_LIBRARY_PATH=動態庫的路徑; 而後倒入環境變量: export LD_LIBRARY_PATH
477 b.(永久設置。)修改動態連接器的配置文件:
478 c.(修改家目錄的 .bashrc文件);
479 7.動態庫的優缺點:
480 優勢:多進程共享一份庫文件,節省內存,易於更新 。
481 缺點:相較於靜態庫而言庫函數訪問略慢。
482 14.使用靜態庫的參數操做動態庫,看可否跑起來。(不能加靜態庫的操做參數)
483
484 "-----第四天-----------------------------------------------------------------------------"
485 15. 其餘命令:
486 1) alias 當前命令="增強版的命令";
487 alias gcc='gcc -std=c99'; 使gcc 的默認編譯按照 c99 規範。(在家目錄的bashrc配置文件中);
488 2)echo 取變量的值:echo $變量名;(取出變量的值)變量名前加 $;
489 例如:echo $PATH;(取出環境變量的值);
490 "取最近的函數的返回值: echo $? "
491 十一。windows中的動態庫
492 1. xxx.dll(windows中的動態庫名後綴);
493 2." 動態庫與靜態庫發佈時的區別:"
494
495
496 十二。gdb 調試:
497 1.獲得包含調試信息的可執行性程序:
498 gdb -g main.c -o app -I ../include ;
499
500 2.運行調試程序:
501 gdb 可執行程序名;
502
503 3.命令:
504 1)執行命令:兩種 start 一行一行執行,執行過程當中能夠添加其餘參數調試。
505 run 直接執行到程序結束。
506 2)查看程序內容: l (什麼都不加);l + 行號; l + 函數名; l + 函數名:行號;
507
508 3)加斷點:b 行數 ; 查看斷點信息:i b; 刪除斷點:del b 斷點編號
509
510 4)繼續執行程序:c ; c + 斷點編號(跳到此段的位置); 打印內容:p 變量名; 往下執行一步:n
511
512 5)自動追蹤變量的值:display + 變量名;查看追蹤變量的編號:i display; 取消追蹤: undisplay + 追蹤變量編號
513
514 6)跳出循環:1)設置變量的值:set var 變量名=值;
515 2)在循環的的外面設一個斷點,跳到該斷點。
516
517 7)獲取變量的類型:ptype 變量名;
518
519 8)進入到函數體的內部:s ;跳到下一個斷點: c 。
520
521 9)跳出當前函數:finish;
522
523 10)條件斷點:b 17 if i == 10(當i等於 10 時 17 行打斷點,注意:斷點不能設在 for 循環的那行,不會中止);
524
525 十三. Makefile 文件編寫;
526 掌握內容:
527 一個規則,兩個函數,三個自動變量
528
529 1.命名:makefile; Makefile;
530 2.用途:
531 項目代碼編譯管理;節省編譯項目的時間;
532 3.Makefile 中的規則:
533 目標:依賴;
534 生成一個 app 執行程序;須要依賴的函數;
535 命令:編譯命令;
536
537 標準格式:"目標 : 依賴(依賴這個位置不必定非得有,有的時候是沒有的。以下面的 make clean:)
538 命令"
539 操做界面的:make 目標;==========》
540 4.工做原理:
541 1)若想生成目標,檢查規則中依賴的條件是否存在;若是不存在,尋找是否有規則用來生成該條件
542
543 2)檢查規則中目標是否須要被更新,必須檢查它的全部依賴;依賴中有任何一個被更新,則目標必須被更新。(規則:"依賴文件比目標時間晚,則須要被更新。")
544
545 5.Makefile編譯版本:"makefile中全部的函數都有返回值"
546 1)版本1:
547
548 缺點:效率低,每次修改任意一處,都須要編譯全部的源文件。
549
550 2)版本二:
551
552 缺點:冗餘。
553 "app:main.o div.o mul.o sub.o //第一個條件
554 gcc main.o div.o mul.o sub.o -o app
555
556 main.o:main.c //第一個條件的依賴條件生成
557 gcc -c main.c
558 div.o:div.c
559 gcc -c div.c
560 mul.o:mul.c
561 gcc -c mul.c
562 sub.o:sub.c
563 gcc -c sub.c"
564
565 3)版本三:(使用了變量)
566 1.Makefile中的變量: 變量名=value
567
568 2.Makefile中的自動變量:
569 1)$@: 規則中的目標
570 2)$<: 規則中的第一個依賴
571 3) $^: 規則中的全部的依賴
572 注意: 這三個只能在命令中使用。
573
574 3.Makefile中本身維護的變量:
575 CPPFLAGS=頭文件的路徑;
576
577 缺點:相關的文件不能自動查找
578 "代碼:
579 obj = main.o div.o mul.o sub.o
580 target = app3
581 CPPFLAGS=-I ../aa/
582
583 #第一條目標
584 $(target):$(obj)
585 gcc $(obj) -o $(target)
586
587 #第二條目標
588 %.o : %.c
589 gcc -c $< $(CPPFLAGS)"
590
591
592 4) 版本四:
593 1.makefile 中的函數:
594 1)全部的函數都有返回值
595 2)wildcard---查找指定目錄下指定類型的文件
596 "src = $(wildcard ./*.c);"
597 patsubst---匹配替換
598 obj = $(patsubst %.c,%.o,$(src))
599 缺點: 功能不夠強大
600 "代碼:
601 src = $(wildcard ./*.c)
602 target = app
603 obj = $(patsubst %.c, %.o, $(src))
604 CPPFLAGS = -I ./
605
606 $(target):$(obj)
607 gcc $(obj) -o $(target)
608
609 %.o:%.c
610 gcc -c $< $(CPPFLAGS)"
611
612 5) 版本五:刪除編寫過程當中的臨時文件
613 1.生成一個與終極目標無關的目標:clean
614 make clean
615
616 1.聲明僞目標:.PHONY:變量的名;
617 僞目標特色:makefile 不會檢查目錄下是否有這樣的文件,也不會對它的時間作檢查
618
619 2.-的做用:、該命令若是錯誤,跳過該命令,繼續執行下一條命令。
620 clean:
621 -rm $(obj); 有提示:(當前命令沒法執行時有提示)
622 -f的做用:強制刪除當前
623 -rm -f $(obj); 無提示:(當前命令沒法執行時無提示)
624 "代碼
625 src = $(wildcard ./*.c)
626 target = app
627 obj = $(patsubst %.c, %.o, $(src))
628 CPPFLAGS = -I ./
629
630 $(target):$(obj)
631 gcc $(obj) -o $(target)
632
633 %.o:%.c
634 gcc -c $< $(CPPFLAGS)
635 .PHONY:clean
636 clean:
637 -rm -f $(obj)"
638
639 終極目標:第一條目標所依賴的規則;
640 "每級目標時間比每級依賴時間晚。"
641
642 十四。linux系統的 IO 函數:
643 linux 每運行一個程序(進程),操做系統都會爲其分配一個 0~4G 的虛擬內存空間(32位操做系統)。
644
645 1.C庫函數:
646 1)fopen 函數返回值:一個文件指針(結構體):(包含三個方面:1.文件描述符, 2.文件讀寫位置, 3.I/O緩衝區(內存地址));
647 文件描述符:描述符表:至關於一個數組,大小爲1024;
648 一個進程最多打開1024個文件;
649
650 2)緩衝區的數據往磁盤上寫內容的三種狀況:
651 1.刷新緩衝區:(fflush)
652 2.緩衝區已滿;
653 3.正常關閉文件(fclose); 或者:main函數中(return, exit);
654 "注意:標準C庫函數 有緩衝區,而linux 系統函數 沒有緩衝區 ";
655 3)ELF(Linux下可執行程序的格式):
656 ELF中存放的是源代碼,他有一個入口,main函數。主要分爲三段:.bss(未初始化的全局變量);.data(已初始化的全局變量); text(代碼段) ;
657
658
659 4) PCB:進程控制塊;其中有一個文件描述表(其中存儲文件描述符;一個文件佔用一個文件描述符),是一個數組,有1024個大小;因此一個進程以內最多隻能打開1024個文件。
660 每打開一個新文件,則佔用一個文件按描述符,並且使用的是空閒的最小的一個文件描述符。
661
662 "代碼區是棧模型"。
663
664
665
666 "-----第五天-----------------------------------------------------------------------------"
667 一.系統 I/O 函數:
668 1.open() 函數當文件不存在時,建立文件,併爲它指定權限;(函數的第二個參數,各類宏定義; 第三個參數:指定權限,與掩碼的取反再按位與得出文件最後的權限)。;
669 1)正常打開, 2)建立文件; 3)文件截斷;
670 2.文件截斷:
671
672 3. perror() 函數的使用:頭文件stdio.h; 打印錯誤信息。;
673
674 4. read() ; size_t(無符號整型); ssize_t(有符號整型);(UNIX 的類型);
675
676 5. linux系統函數的注意事項:須要判斷函數的返回值。-1,失敗;
677
678 6.Linux系統函數實現文件的拓展:
679 第一步 lseek(fd, 1000, SEEK_END );
680 第二步 write(fd, "a", 1); (必須有一次寫操做)。
681 "拓展的部分爲空洞文字;有空洞文字的文件叫空洞文件,做用: 提早佔用磁盤空間,下載中的應用:防止下載一半,空間不夠。"
682
683 7.stat()函數:
684 1.off_t(unix 中的整型);
685 2.應用(斷點續傳;)
686
687
688 8.一些命令的穿透功能:如:vi; cat; (遇到軟鏈接時)
689 不穿透的:如: rm; (遇到軟鏈接時)
690
691 9.chmod()
692
693 10.chown()函數的參數查找;必須在配置文件中查找
694
695 11.unlink()函數;(刪除文件目錄項,使之具有被釋放的條件。)
696 函數使用場景:實現可以自動刪除臨時文件;
697 注意點:當文件在打開狀態時:open(),並無關閉;unlink,當close的文件的時候,會自動刪除。
698 "例如:
699 int fd = open("san.txt", O_RDWR);
700 unlink("san,txt"); //刪除文件,當前狀態不會刪除
701 write(fd, buf1, 102);
702 lseek();
703 read(fd, buf, 200);
704 close(fd); //此時文件 san.txt 纔會自動刪除
705 "
706 12.chdir:修改當前進程的路徑
707 int chdir(const char *path); path:當前進程的名字。
708
709 13.getcwd:獲取當前進程的工做路徑。char* getcwd(char* buf, size_t size);
710 參數:buf--緩衝區,存儲獲取到的工做路徑。
711 size--緩衝區的最大容量。
712
713 14.mkdir--建立目錄: int mkdir(const char* pathname, mode_t mode );
714 參數: pathname: 建立的目錄名。 mode: 目錄權限(8進制)。給出的權限通過換算以後纔會獲得最終權限。(mode & ~umask & 0777)
715
716
717
718
719
720 "-----第六天-----------------------------------------------------------------------------"
721
722 1.版本控制:svn/git;
723
724 2.進程的概念:
725 1)程序和進程;
726 每一個進程操做系統會爲它分配 0-4G 的虛擬內存空間(32位操做系統); 其中0-3G爲用戶內存空間,進程能夠對它進行讀寫操做; 3G - 4G 爲系統內核空間,進程沒有讀寫權限。
727 進程只能讀寫用戶空間,沒有權限讀寫內核空間(kernel);
728 2)內存頁面的概念
729 操做系統是按頁來管理內存的;每一個頁有4096個字節。
730 還能夠設置頁面屬性:如char *str = "hello",字符串在只讀數據段,此時只能讀,不能寫。
731
732 3)進程的4種形態:0-3級; 0 級(內核態),最高; 3級(用戶態);最低。
733
734 2)併發:
735 3)單道程序設計/多道程序設計
736 4)CPU/MMU
737 5)PCB:結構體;其中有一個指針指向文件描述符表;文件描述符表中存儲1024個指針;已經打開的文件結構體。
738 每一個進程有屬於本身的PCB(進程的狀態描述符);可是多個進程只有一個內核區。
739 3.環境變量控制
740 1)echo $名稱; 查看該名稱的環境變量。
741 2)查看系統的環境變量: env;
742 3)獲取環境變量的值:char *getenv(const char* name); 獲取鍵name環境變量的值。
743 4)設置環境變量:int setenv(const char *name, const char *value, int rewrite); 將環境變量name的值設置爲 value。
744 若是環境變量 name 已存在;則 rewrite 非0,覆蓋原來的環境變量;rewrite爲0,則不覆蓋原來的環境變量。
745 5)刪除環境變量: void unsetenv(const char *name) 刪除 name 的定義;
746
747 6)進程裏能夠設置本身的環境變量,避免設置在終端,影響他人。
748 4.環境控制原語:
749 1)fork:
750 2)wait/waitpid
751 3)
752
753 5. printenv.c
754
755 6.進程的狀態:4 種或 5 種,都對。 就緒, 運行, 睡眠, 中止。
756
757 7.CPU的組成狀態: 運算器,寄存器,控制器,譯碼器。
758
759 操做系統完成進程調度。(cpu進行時鐘週期運算)
760 cpu的分時複用功能,使進程看起來像多進程。
761 在單核 cpu 上,同一時間只能有一個進程處於運行狀態。那麼多核 cpu,就能夠有多個進程處於運行狀態。
762 "8.子進程、父進程間的共享、不共享:"
763 共享: 1.宿主目錄; 2.進程工做目錄; 3.信號處理方式; 4.環境變量;
764 5. 0-3G的用戶空間("讀時共享,寫時複製。"「特別是:全局變量」) 6.文件描述符(打開文件的結構體) 7.mmap創建的映射區。
765
766 不共享:1.進程ID, 2.進程運行時間 3.鬧鐘; 4.未決信號集 5.PCB
767
768 8.進程原語:
769 1)建立子進程。pid_t fork(); 調用1次,返回兩次;在父進程返回子進程的 PID, 在子進程返回0.
770 2) fork()的工做進程:先調用 creat(),建立一個進程, 在調用 clone(),給子進程複製父進程的內容;
771 3)pid = fork(); //此時父子進程就都出來了。
772 4)pid_t getpid(); 返回調用進程的PID號;
773 pid_t getppid(); 返回調用進程的父進程的PID號
774 當在子進程中 getpid(),獲得的值與 fork()父進程的返回值相等,都是這個子進程的id號
775 5)父子進程:讀時共享,寫時複製。
776 6)最大建立進程 個數;
777 9. uid_t getuid(void); //返回實際用戶id;
778 uid_t geteuid(void); //返回有效用戶id;
779 "注意: 文件實際用戶與有效用戶在建立該文件的家目錄下時,若是沒有修改,此時是相通的。
780 當文件被拷貝到root目錄時, "
781 設置用戶id; chmod 04755; 4 是設置用戶ID。 完後效果爲 -rwsr-xr-x; s表示設置了用戶ID。
782 做用:當執行此文件時,執行者有效用戶ID變爲此文件的全部者。
783 設置用戶組ID: chmod 06777; 6 是設置用戶ID和組ID; 效果爲: -rwsrwsrwx;
784
785 10. exec族函數的使用:
786 1)功能: 去磁盤中加載另外一個可執行程序,用它的代碼段、數據段替換掉當前可執行程序的代碼段、數據段;而後從後加載的這個程序退出,被替換的程序後續代碼就不執行了。(換核不換殼,)
787 2)通常狀況下:與 fork() 函數聯合使用;。 同時exec族函數不會建立新進程, 因此該程序的 ID 不會改變。
788
789 3)函數的返回值: 成功沒有返回值,運行完畢,本身退出。
790 失敗返回 -1;
791 4)exec族函數的規律: l(list):命令行參數列表。 p(path): 搜索file時使用path變量。
792 v(vector):使用命令行參數數組。 e(environment):使用環境變量的數組,不使用進程原有的環境變量,設置新加載程序的環境變量;
793
794 5)int execl(const char *path, const char *argc, ...);
795 例如:execl("./bin/ls", "ls", "-l", "-a", NULL); 這幾個參數的做用:其中第一個參數:"./bin/ls",命令的環境變量(即所在文件),不能夠改變,必須完整正確;
796 "ls":佔位參數,能夠隨便寫,通常寫成該命令。(不能缺失,若是缺失了,就會把後面的命令參數變爲佔位參數,輸出結果會出錯。) "-l","-a"該命令的參數。 NULL:衛兵,執行到這裏時命令結束。
797
798 11. toupper():將小寫字母變爲大寫。
799
800 12.殭屍進程,孤兒進程:
801 1)概念:
802 殭屍進程:子進程終止,父進程未回收,子進程殘留資源(PCB)存放於內核,形成殭屍進程。
803 孤兒進程:父進程先於子進程終止,則子進程成爲孤兒進程,而後被init進程領養。
804
805 1)S:睡眠狀態; Z:殭屍狀態;
806 2)殭屍進程的產生緣由:用戶空間釋放,內核空間的PCB沒有釋放,等着父進程回收。(它消耗的是內核當中的內存資源)
807 即:子進程退出,父進程沒有回收子進程資源(PCB),則子進程變爲殭屍進程。
808 3)子進程的PCB(在內核空間)沒有釋放,是留給父進程回收用的。只有父進程回收後,殭屍進程纔會消失。
809 4)殺死殭屍進程的辦法是殺掉它的父進程。
810
811 孤兒進程:父進程先於子進程結束,則子進程變爲孤兒進程,子進程的變爲1號進程init進程,由1號進程領養。
812
813 "殭屍進程比孤兒進程更危險, 由於它不會自動關;,而孤兒進程會由 1 號進程領養,當它執行完畢後,會被 1 號進程回收"。
814 作開發時主要避免的是殭屍進程的產生。用 wait(); waitpid(); 來避免殭屍進程的產生。
815
816
817 13. pid_t wait(int* status); (阻塞函數,等待回收子進程資源;若是沒有子進程,返回-1);
818 1)返回值:回收的子進程的ID號, wait(NULL);不關心子進程如何死亡,直接回收。
819 wait(&st); 用st來保存子進程死亡時的狀態。
820
821 2) 父進程的ID與它的進程組ID相同;子進程的組ID與父進程的ID相同。
822 kill -9 -父進程的ID(即組進程的ID),這個進程組的全部進程都被殺死。"(注意 - 不能少)"
823
824 14.pid_t waitpid(pid_t pid, int *status, int options); (設置非阻塞。)
825 第一個參數 pid的值類型: 1) < -1; 回收指定進程組內的任意子進程。(由於父進程與子進程屬於統一進程組,父進程與孫子進程屬於不一樣的進程組,可是他們有血緣關係。)
826 -1;回收任意子進程(只要有血緣關係就行。)
827 0; 回收 當前調用 waitpid 一個進程組的全部子進程。
828 > 0; 回收指定ID的子進程。
829 第二個參數:保存子進程的推出狀態。
830
831 第三個參數:WNOHANG:若是沒有子進程退出,當即返回。(實現了非阻塞的 wait).
832
833 15. 阻塞函數:非阻塞函數:在文件open(O_NONBLOCK)的時設置宏;讀常規文件不會出現阻塞,當讀僞文件時會出現。
834 例如:阻塞讀終端; 管道; 網絡;
835
836 設置非阻塞後:應設置輪詢。
837
838
839 "=========進程間的通訊(IPC)==========================================================================================================="
840 一。IPC方法:Linux環境下,多個進程間的通訊,須要經過內核,在內核中開闢一塊緩衝區(賦予他用戶權限);進程1把數據從用戶空間拷貝到內核緩衝區,
841 進程2 把數據從內核緩衝區拷讀走,內核提供的這種機制稱爲進程間的通訊(IPC)。
842
843 進程間的通訊;四種方法:1.pipe管道 2.fifo有名管道,3.內存共享映射 4.Unix Domain Socket;
844 管道(使用最簡單);信號(開銷最小);共享映射區(速度最快,效率最高); 本地套接字(最穩定);
845
846 二。pipe管道:
847 1.管道的特性:數據只能一個讀,一個寫,必須是一個方向。
848 半雙工:數據同一時刻只能有一個流向。即只能父進程寫,子進程讀; 或子進程寫, 父進程讀。
849 全雙工:數據同一時刻能夠兩個方向。
850 單工:數據只能同一個方向流動。
851 dup2(int oldfd, int newfd); 將第一個參數拷貝給第二個參數。
852 1.其本質是一個僞文件(實爲內核緩衝區)
853 2.有兩個文件描述符引用,一個讀端,一個寫端。
854 3.規定數據從管道的寫端流入,從讀端流出。
855
856 管道的原理:管道實爲內核使用環形隊列機制,藉助內核緩衝區(4K)實現的。
857
858 管道的侷限性:1.數據不能本身寫,本身讀;
859 2.管道中的數據不能反覆讀取,一旦讀走,管道中再也不存在。
860 3.採用半雙工通訊方式,數據只能在單方向上流動。
861 4.只能在有血緣關係之間的進程使用管道。
862 5.只能進行單向通訊,雙向通訊須要創建兩個管道。
863
864 2. pipe()建立管道,用於有血緣關係之間的通訊。(採用環形隊列實現的)
865 管道使用半雙工通訊; 建立完管道完後,肯定通訊方向:父寫子讀,或子寫父讀。
866 若是想建立多條管道,必定要先pipe(),再fork(),使子進程得以繼承管道。
867
868 使用管道時的四種注意狀況:
869 1) 寫段關閉,讀端讀完管道里的內容時;再次讀,返回0,至關於讀到文件末尾EOF;
870 2)寫端未關閉,寫端無數據, 讀端讀完管道里的數據時,再次讀,阻塞。
871 3)讀端關閉, 寫段寫管道,產生SIGPIPE信號,寫進程默認狀況下會終止進程。
872 4)讀端未讀管道數據,當寫段寫滿管道後,在此寫,阻塞。
873 5)使用管道,無須open,但需手動close。
874
875 管道的緩衝區大小:1.函數的方法:fpathconf(int fd, int name); 第一個參數爲管道描述符;第二個參數爲狀況標識符。
876 2.命令: ulimit -a; 查看系統 軟硬件限制。
877
878 3. 總結:
879 1.讀管道:
880 1.管道中有數據,read返回實際讀到的字節數;
881 2.管道中無數據,寫端都被關閉,read返回 0,至關於讀到文件末尾;
882 寫端未關閉,read函數阻塞等待,(期待不久的未來會有數據到來,但此時會讓出CPU資源)
883 2.寫管道:
884 1.管道讀端所有關閉;進程異常停止(返回一個終止信號);
885 2.管道讀端未關閉:
886 1)管道已寫滿,write阻塞等待
887
888 2)管道未寫滿,write將數據寫入,返回實際寫入的字節數;
889
890
891 "==========================================================================="
892 4.設置非阻塞管道的兩種辦法:
893 1)fcntl函數設置非阻塞管道;
894 int flg = fcntl(fd, F_GETFD);
895 flg |= O_NONBLOCK;
896 fcntl(fd, F_SETFL, flg);
897 2)打開文件時直接設置非阻塞;
898 int fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
899 當讀取一個非阻塞文件,可是此時沒有內容,會出錯,錯誤碼爲EAGAIN;
900 5. read() 函數的返回值四種狀況;因爲非阻塞設置的存在.
901 1.返回值 > 0; 讀到的字節數
902 2.返回值 < 0; 讀到文件末尾
903 3.返回值 == -1;可是errno != EAGAIN 或 EWOULDBLOCK
904 if( ret == -1) {
905 if(errno == EAGAIN)
906 {
907 說明文件被設置爲非阻塞方式讀取,此時數據沒有到達。
908 }
909 else
910 {
911 失敗;
912 }
913 }
914 4.返回值 == -1, 可是errno == EAGAIN 或 EWOULDBLOCK;
915 說明此時文件被設置爲非阻塞方式讀取,數據尚未到達。
916 "========================================================================"
917 三. fifo有名管道:解決無血緣關係的進程通訊;
918 1.介紹:
919 FIFO文件在磁盤上沒有數據塊,僅僅用來標識內核中的一條管道。各進程能夠打開這個文件進行read/write,其實是在寫內核通道,這樣就實現了進程間的通訊。
920 1.建立fifo的方法:
921 1)在終端建立一個有名管道;(不經常使用)用命令;"mkfifo 管道名";
922 2)在代碼運行時建立一個有名管道;(經常使用)用函數;int mkfifo(const char*pathname, mode_t mode);成功返回 0,失敗-1;
923
924 2.利用fifo實現非血緣關係進程間通訊
925 1.進程使用 「同一個fifo」 完成進程間通訊。
926 2.一個進程以只讀方式打開read端,一個程序以只寫打開寫段。
927 3.一根管道能夠打開多個讀端,多個寫段。(一個寫段多個讀端; 或 一個讀端多個寫段);
928
929 3.多種特殊狀況:
930 當一個寫端多個讀端時: 每一個讀端讀取到的數據都不相同,由於從管道中讀數據,讀走以後,管道中的這個數據就不存在了;此時每一個讀端讀到的全部內容合在一塊兒爲
931 管道寫端寫入的數據
932 當多個寫端一個讀端時, 每一個寫端寫入的數據都會被這個讀端讀取出來;此時管道讀到的數據爲全部寫端寫入的數據。
933
934 四。mmap 內存映射:
935
936 從磁盤映射到kernel區,同時kernel區這段內存(映射佔用的)開放了用戶區的權限;因此進程能夠進行訪問
937
938 1.文件是應用於進程間通訊
939 1)父子進程之間
940 能夠用文件進行通訊;
941 2)非血緣關係進程間通訊
942 能夠用文件進行通訊;
943
944 2.創建映射區,完成進程間通訊
945 1)mmap函數;六個參數的不一樣意義
946
947 2)注意事項
948 1.open的時候能夠建立一個新文件,可是用此文件建立映射區時,大小不能爲0;(能夠進行文件拓展後再用來建立映射)
949 mmap使用的時候常常出現總線錯誤,一般是因爲共享文件存儲空間大小引發的。
950
951 2.建立映射區的時候, 隱含着一次對文件的讀操做;因此文件打開的方式只能爲"讀寫;或讀"。
952 當 MAP_SHARED(對內存的修改將反應到磁盤空間) 時,要求 映射區的權限 <= 文件打開的權限。
953 當 MAP_PRIVATE(對內存修改不會反應到磁盤空間) 時,此時則沒有要求。(mmap中的權限是對內存的限制);
954
955 3.映射區建立完後關閉文件按描述符,對映射區沒有影響。
956 4."最後一個參數,偏移量必須是4K的整數倍。"
957 5.munmap函數傳入的地址必定要是mmap的返回地址。堅定杜絕對mmap函數的返回值進行++操做
958 6.mmap建立映射區出錯的機率很是高,必須進行出錯判斷。
959
960 3)父子進程間的mmap(用戶空間獨立,內核去各進程共享。)
961 1.先mmap建立映射區
962 2.再fork()共享映射區內存首地址
963 3.指定MAP_SHARED;(必須是 SHARED);
964
965 4)非血緣關係進程間通訊
966 1.使用「同一個文件」建立映射區
967 2.兩個進程,一個以read映射區,一個以write方式打開映射區;
968 3.指定 MAP_SHARED;
969 4)MAP_ANONYMOUS(匿名映射); 不能夠用來通訊
970 5)/dev/zero(系統的僞文件); 不能夠用來通訊
971 5)匿名映射
972 linux 建立匿名映射:第四個參數添加 MAP_ANON或MAP__ANONYMOUS;(注意這個匿名宏,只有Linux操做系統可使用)。
973
974 UNIX(沒有上述的匿名宏)。使用系統中的特殊文件(/dev/zero;(無限讀,能夠用來建立匿名映射))
975
976 3.數據能夠重複讀取;(即多個讀端讀取一個寫端,讀取的內容相同,與fifo不一樣,取決於讀取的數據)。
977
978
979
980 "====================進程間的通訊(IPC)================================================================================================"
981
982 文件名最大爲255字節(byte);
983 "============================硬連接========================"
984 建立一個硬連接:
985 1.dentry(包含文件名,文件屬性)
986 2.一個文件包含(三大塊):文件的名字; inode(指向文件屬性) ;文件內容;
987 3.
988 "============================硬連接========================"
989
990 strace 跟蹤程序的運行時函數的系統調用;
991
992 "===信號========================================================================================================================"
993 一.信號的概念:
994 1.本質:
995 軟中端;信號經過內核發送,內核處理的。
996 2.特性:
997 1)簡單,2)不能攜帶大量信息; 3)知足某一條件
998 3.信號機制:
999 軟中端;信號經過內核發送,內核處理的;經過軟件的方法實現的,有較強的延遲性。
1000
1001 3.四要素:
1002 1.信號編號, 2.信號名稱, 3。默認處理動做,4.對應的事件。
1003
1004 2.信號的默認處理動做(5種):
1005 1.終止進程(term);2.忽略(Ign:信號被處理丟棄);3.終止進程併產生core文件(core);
1006 4.Stop(暫停); 5.Cont (繼續);
1007
1008 4.名詞稱呼
1009 1.信號的狀態:
1010 1.產生;
1011 2.未決:處於產生和遞達中間,因爲阻塞不能遞達、處理。
1012 3.遞達;信號遞達後內核會當即處理。(也就是說,他倆常常綁定在一塊兒,信號遞達就表明這信號被處理。)
1013 4.處理:(信號必須遞達)
1014 1.忽略處理(信號已經處理,丟棄操做); 2.執行默認操做, 3.捕捉(不執行默認操做,來指定操做讓其執行;)
1015
1016 2.未決信號集:(pending)
1017 在PCB中,以位圖的方式存在。
1018 記錄信號是否被產生,而且被處理。 內核處理信號的依據。用戶不能直接修改未決信號集。
1019
1020 3.阻塞信號集/信號屏蔽字:(mask)
1021 在PCB中,以位圖的方式存在。 mask影響pending;用戶只能夠經過mask來影響pending。
1022 記錄信號是否被設置屏蔽。用戶影響信號的依據。
1023
1024 4. 1-31 號信號,常規信號(不支持排隊); 34-64 號信號,實時信號(支持排隊)
1025
1026 5.特殊信號:(兩個);
1027 9 號、 19 號信號;不容許捕捉,忽略,甚至不能設置屏蔽。
1028
1029 6.產生段錯誤的方式(三種);
1030 1.訪問非訪問區域。0x1000 printf(); mmu---沒有映射該虛擬內存
1031 2.對只讀區域進行寫操做。 char* p = hello; p[1] = 'H'; mmu---映射的虛擬內存對應的物理內存權限不足。 0 內核權限; 3 用戶權限
1032 3.內存溢出; char buf[10]; buf[10] = '10'; buf[100] = '28'; mmu---沒有映射該虛擬內存。
1033
1034 二.產生信號:
1035 1.常見的產生信號方法:
1036 1.按鍵產生:ctrl+c;
1037 2.系統調用:如kill
1038 kill(pid_t pid, int sig); 向指定進程或進程組發送指定信號;
1039 第一個參數: pid > 0; 向指定進程發送指定信號; pid == 0; 向調用kill函數的進程組的全部進程發送該信號
1040 pid == -1; 發送信號給系統中有權限的全部進程; pid < -1; 發送信號給指定的進程組|pid|;
1041 第二個參數: 信號。(不一樣的平臺環境下,信號的編號不一樣;可是信號的宏定義相同,因此通常使用宏名)。
1042
1043 raise() 給當前進程發送指定信號;
1044 abort() 向當前進程發送SIGABRT信號;
1045 3.軟件條件產生:如,定時器alarm;
1046 alarm:每一個進程有且只有惟一一個定時器。
1047 返回值特殊:上次定時剩餘的時間。定時(採用天然定時),與進程狀態無關!!!,不管處於何種狀態,都會計時。;
1048 取消鬧鐘: alarm(0); 實際執行時間 = 系統時間+用戶時間+等待時間。
1049 定時的單位是:秒。
1050 setitimer(); 定時單位單位:微妙;
1051 三個參數:
1052
1053
1054 4.硬件異常產生:如,非法內存訪問(段錯誤);內存對齊出錯(總線錯誤);除0(浮點數除外)。
1055
1056
1057 5.命令產生:如kill命令
1058
1059 三。信號操做函數;
1060 1.信號集 set:
1061 sigset_t set;
1062
1063 sigemptyset(&set) 清空集合
1064
1065 sigfillset(&set) 置1集合
1066
1067 sigaddset(&set, 待添加的信號名稱) 添加信號到集合中
1068
1069 sigdelset(&set, 待刪除的信號名稱) 刪除信號到集合中
1070
1071 sigismember(&set, 待判斷的信號名稱)判斷信號是否在集合中 -- 》 1:在 0:不在; -1;錯
1072
1073 2.mask(信號屏蔽字/阻塞信號集)操做
1074 sigprocmask();用來屏蔽信號、解除信號;其本質是讀取或修改進程的信號屏蔽字(PCB中);
1075 "注意:屏蔽信號只是將信號處理延後執行(延至解除屏蔽), 而忽略表示將信號丟棄。"
1076 參數:第一個參數 how 的取值:假設當前的信號屏蔽字爲mask;
1077 1.SIG_BLOCK:當how設置爲此時,set表示要屏蔽的信號。至關於mask= mask|set;
1078 2.SIG_UNBLOCK:當how 設置爲此時,set 表示要解除的信號。至關於:mask = mask & ~set;
1079 3.SIG_SETMASK; 當how 設置爲此時,set = mask;
1080 第二個參數: set 傳入參數:用來操做mask的set集合。
1081 第三個參數: oldset 傳出參數。記錄舊有的mask狀態。
1082
1083 3.pending操做
1084 int sigpending(sigset_t *set);傳出參數
1085 參數:獲取未決信號集
1086 返回值:存在返回 1; 不存在返回 0;
1087
1088 四。信號捕捉
1089 1.signal:(註冊信號的捕捉處理函數)
1090 參數:1.信號編號 2.捕捉後調用的執行函數(是一個函數指針。即回調函數);
1091 返回值:捕捉的函數句柄。
1092
1093 2.sigaction: 1)信號捕捉函數執行期間,本信號被自動屏蔽(取決於:sa_flags) 2)信號捕捉函數執行期間,信號屢次產生,只記錄一次。
1094
1095 函數原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
1096 參數解析: 1)第一個參數:信號名稱或編號;要捕捉的信號。
1097 2)第二個參數:新處理動做傳入,是一個結構體。
1098 1)sa_handler: 1)函數指針,捕捉信號後執行的回調函數;2) SIG_IGN 表示忽略; 3)SIG_DFL 表示執行默認操做。
1099 2)sa_mask; 信號屏蔽字/阻塞信號集;捕捉函數執行期間的屏蔽字,此中的信號在捕捉函數執行期間自動屏蔽。
1100 3)sa_flags: 1) 0; 表示:信號捕捉函數執行期間,要捕捉的信號被自動屏蔽(即第一個參數)。
1101 2)SA_SIGINFO: 選用sa_sigaction來指定捕捉函數;
1102 3)SA_INTERRUPT: 系統調用被信號中斷後,不重啓;
1103 4)SA_REATART: 系統調用被信號中斷後,自動重啓。
1104 5)SA_NODEFER: 在捕捉函數執行期間不自動屏蔽捕捉的信號;
1105
1106 4) sa_sigaction: 函數指針, 三個參數,void (*sa_sigaction)(int, siginfo_t*, void*);指定帶參數的信號捕捉函數。
1107 3)第三個參數:舊處理動做傳出;
1108 返回值: 0 表示成功, -1 表示失敗,並設置errno ;
1109 3.信號捕捉特性:
1110 1)捕捉函數執行期間,屏蔽字由sa_mask指定。
1111 2)捕捉函數執行期間,被捕捉的信號自動屏蔽; 由sa_flags = 0 決定;
1112 3)"捕捉函數執行期間,常規信號不支持排隊,屢次產生只記錄一次。"
1113 常規信號爲:1-31 信號; 實時信號爲 34-64 信號。
1114 詳細過程:進程正常運行時,默認PCB中有一個信號屏蔽字,假定爲☆,它決定了進程自動屏蔽哪些信號。當註冊了某個信號捕捉函數,捕捉到該信號之後,
1115 要調用該函數。而該函數有可能執行很長時間,在這期間所屏蔽的信號不禁☆來指定。而是用sa_mask來指定。調用完信號處理函數,再恢復爲☆。
1116
1117 4.信號內核實現捕捉函數思想:
1118 信號捕捉函數是 回調函數; 由內核在信號產生、遞達以後負責回調。
1119 調用結束應該返回內核空間,再返回用戶空間。
1120
1121 5.內核實現信號捕捉的通常過程
1122 1)回調捕捉函數; 2)調用結束先返回內核。
1123
1124 「注意:此處加圖片:」
1125 五。竟態條件(時序竟態)
1126 1.pause() 函數:主動形成進程掛起,等待信號喚醒。調用該系統調用的進程將處於阻塞狀態(主動放棄CPU),知道有信號到達將其喚醒。
1127 int pause(void); 返回值:-1,並設置errno == EINTR;
1128 注意:
1129 1) 喚醒pause()函數的信號不能執行默認操做、忽略、屏蔽。緣由:
1130 1)若是信號的默認動做是終止進程,則進程終止,pause函數不會有機會被調用。
1131 2)若是信號默認動做是忽略、屏蔽,則進程繼續掛起,pause不會調用。
1132 2)若是信號的處理動做是捕捉,則【捕捉函數處理完後,pause被調用返回-1,而且errno == EINTR,表示被信號終端,即喚醒】;
1133 3)綜上所訴:能喚醒pause()函數的信號,只能是被捕捉的信號;
1134
1135 2.時序竟態:
1136 1.時序問題產生的緣由: 1)系統負載嚴重; 2) 信號不可靠機制;
1137
1138 2.解決時序問題:
1139 1)使用原子操做;將解除信號屏蔽與掛起等待合併成一個步驟。sigsuspend() 函數具備這個功能。在對時序要求嚴格的場合下都應用
1140 sigsuspend 替換 pause。"(解除信號屏蔽+掛起等待信號)----》原子操做---》sigsuspend()函數"
1141 int sigsuspend(const sigset_t *mask); 掛起等待信號。
1142 函數詳解: 1)主動形成進程掛起,等待信號; 2)在這個函數調用期間屏蔽字由它的參數決定; 3)函數調用結束屏蔽字恢復爲原值;4)原子操做
1143 2)提前預見,主動規避。這種錯誤,無法用gdb調試出來。
1144
1145 3.全局變量的異步IO:
1146 存在的問題:
1147 1.多個進程對 同一 個全局變量進行寫操做,存在問題。(如:信號回調函數中的全局變量和主函數中的全局變量爲同1個,內核進程和主進程都對
1148 全局變量進行了寫操做,很是容易出問題)。
1149 2.寫操做時沒有任何 同步 機制。(加鎖機制)
1150
1151 「注意:此處有代碼,父子進程數數,代碼1,主進程和內核對同一個全局變量進行寫操做,出問題;
1152 代碼2,全局變量只由主進程進行一次賦值操做後,主進程和內核進程對它的只讀操做,沒有出問題」
1153
1154 4.可重入、不可重入函數:
1155 注意:
1156 1)不可重入函數:函數內部含有全局變量、靜態變量,使用malloc、free;
1157 "2)信號捕捉函數應設計爲可重入函數;(與上面的相反的就是可重入函數)。"
1158 3)信號處理程序調用的可重入的系統調用函數;可參閱 man 7 signal;
1159 4)沒有包含在上述列表中的系統調用函數大多數是不可重入的,其緣由是:
1160 a) 使用了靜態數據結構,
1161 b) 調用了malloc 或free
1162 c) 是標準I/O函數 ;
1163
1164
1165 六。SIGCHLD信號 -------IGN(該信號的默認動做是忽略)
1166 1.該信號的產生:
1167 1)子進程終止;
1168 2)子進程接收到SIGSTOP信號中止時;
1169 3)子進程處在中止態,接收到SIGCONT後喚醒時;
1170 綜上所述:只要子進程的狀態發生變化,會對父進程發出SIGCHLD信號,默認處理的動做是忽略。
1171
1172 2.藉助 SIGCHLD 子進程回收。
1173 1)wait()--------阻塞等待子進程結束;
1174 2)waitpid()--------設置不阻塞(第二個參數WNOHANG)。若是這樣設置,要設置輪詢,才能將子進程回收。
1175 3)信號捕捉---子進程回收;
1176
1177 3.注意:
1178 1)子進程繼承了父進程的 信號處理動做和 信號屏蔽字(mask),但並無繼承父進程的 未決信號集(sigpending)。
1179 2)註冊信號捕捉函數的位置,和與其餘進程發出信號的配合(必須在捕捉信號發出以前完成註冊)。
1180 3)在捕捉函數中回收子進程(多個),必定要用循環,才能夠作到,一次進入回收多個子進程;不然,會有子進程遺漏,未被回收,形成殭屍進程。
1181
1182 「參考代碼」
1183
1184 七。信號傳參:
1185 1.int sigqueue(pid_t pid, int sig, const union sigval value); 成功返回0; 失敗-1;
1186 sigqueue 向指定進程發送信號的同時攜帶參數(即它的第三個參數);
1187 "注意:攜帶的數據。若是攜帶的是 地址:需注意,不一樣進程之間虛擬地址空間各自獨立,將當前進程地址傳遞給另外一進程沒有實際意義"
1188 2.捕捉信號傳參
1189 1)用該函數捕捉信號傳遞的數據: int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
1190 2)當註冊信號捕捉函數,但願得到更多關於該信號的信息,不該使用 sa_handler, 而應使用 sa_sigaction。 但同時 sa_flags 必須指定SA_SIGINFO.
1191 siginfo_t 是一個成員十分豐富的結構體,攜帶者該信號的各類相關信息。
1192
1193 八。中斷系統調用
1194 1.慢速系統調用(形成當前系統永久阻塞的)
1195 1)如read, write, wait, pause, sigsuspend, 都是慢速系統調用 ;
1196 2)概念: 可能使進程永遠阻塞的一類系統調用;若是再阻塞期間收到一個信號,該系統調用被中斷,再也不繼續執行;也能夠經過設置,使其中斷後再從新啓動。
1197 3)特色:慢速系統調用被中斷的相關行爲,實際上就是pause的行爲: 如read()
1198 1) 信號不能被屏蔽, 執行默認動做, 忽略;
1199 2)信號的處理方式必須被捕捉;
1200 3)中斷後返回-1, 設置errno爲 EINTR(表示:「被信號終端」);
1201
1202 4)設置sa_flags 參數來決定它終端後的行爲:
1203 0 表示被捕捉的信號,在捕捉函數執行期間被自動屏蔽
1204 SA_NODEFER 表示被捕捉的信號,在捕捉函數執行期間不被自動屏蔽
1205 SA_INTERRURT 表示慢速系統調用,若被信號打斷,再也不重啓
1206 SA_RESTART 表示慢速系統調用,若被信號打斷,重啓
1207 SA_SIGINFO 表示捕捉函數是3參的sigaction,需指定爲這個宏名
1208
1209 2.其餘系統調用:
1210 如Lgetpid(), fork();
1211
1212 十。終端
1213 1.字符終端(虛擬終端),圖形終端(僞終端),網絡終端(僞終端)。
1214 2.線路規程(line discipline):
1215 像一個過濾器,對於某些特殊字符並非讓它直接經過,而是作特殊處理,好比ctrl+c,對應的字符並不會被用戶程序read讀到,而是被線路規程截獲,
1216 解釋稱SIGINT信號發送給前臺進程,一般會使該進程中止。線路規程應該過濾哪些字符和作哪些特殊處理是能夠配置的。
1217 3.在終端設備(如鍵盤)上輸入內容進入進程的順序:
1218 終端設備--》終端設備驅動--》line discipline(線路規程過濾)---》系統調用(普通內容)---》用戶進程
1219 ---》內核特殊字符(解釋稱信號)--》內核 前臺進程。;
1220 4.一套僞終端由一個主設備(PTY Master)和一個從設備(PTY Slave)組成;主設備在概念上至關於鍵盤、顯示器,只不過他不是一個真正的硬件而是一個內核模塊;
1221 操做它的也不是用戶,而是另一個內核模塊。 網絡終端或圖形終端窗口的shell進程以及它啓動的其餘進程都認爲本身的控制終端是僞終端從設備。
1222
1223 十一。進程組
1224 pid_t getpgid(pid_t pid); 返回指定進程組的ID
1225 pid_t getpgrp(void); 返回調用函數進程組的ID
1226 int setpgid(pid_t pid, pid_t pgid); 設置某個進程的進程組ID; 成功返回0;失敗-1;
1227 1.當父進程建立子進程時,默認子進程與父進程屬於同一進程組。其進程組ID==父進程的ID。
1228 2.特性:
1229 1)進程組ID == 組長ID
1230 2)進程組的生命週期: 只要進程組中有一個進程存在,該進程組就存在,"與組長進程是否終止無關"。
1231 進程組建立到最後一個進程離開(終止或轉移到另外一個進程組)。
1232 3.一個進程能夠爲本身或子進程設置進程組ID。
1233
1234 4.修改一個進程的進程組ID需注意:
1235 1)如改變子進程爲新的組,應在fork後,exec前。
1236 2)權限問題。非root用戶只能改變本身和它建立的子進程的進程組。
1237
1238 十二。會話。
1239 pid_t getsid(pid_t pid);獲取該進程的會話ID(若是查看當前進程的會話ID,參數爲0就行。本身測試吧)。成功:返回會話ID; 失敗:返回-1,並設置errno .
1240 pid_t setpid(void); 建立一個會話,以本身的ID爲新會話的ID,同時也會成爲一個新的進程組。 成功:返回調用進程的ID;失敗,-1;
1241 1.會話:進程組的集合。
1242 建立會話應注意:
1243 1.建立會話的進程不能是進程組組長;同時建立的進程變成新會話首進程(即組長)。
1244 2.建立完後該進程成爲新進程組的組長進程。
1245 3.須要有root權限;(ubauntu不須要)
1246 4.新會話丟棄原有的控制終端,該會話沒有控制終端(也就沒法與用戶進行交互)。
1247 5.該調用進程是組長進程,則出錯返回。(與1 相同)。
1248 6.新建會話時,先調用fork,父進程退出;子進程建立會話(調用setsid()函數)。
1249
1250 "注意:子進程不會隨着成爲新的進程組組長,而其父進程發生改變。"
1251
1252
1253 十三:守護進程:
1254 1.Daemon(精靈)進程,即守護進程。
1255 特徵: 1.位於Linux後臺,服務進程。
1256 2.獨立於控制終端(即沒有控制終端),週期性的執行某任務,等待某事件
1257 3.不受用戶的註銷、登陸而終止;(注意:不是關機)。
1258 4.一般採用以d結尾的名字。
1259
1260 2.建立守護進程的模型:
1261 1.建立子進程,父進程退出
1262 全部工做在子進程中進行,形式上脫離了控制終端。
1263 2.在子進程中建立新會話
1264 setsid()函數
1265 使子進程徹底獨立出來,脫離控制;
1266
1267 3.改變當前目錄爲根目錄;
1268 chdir()函數;
1269 目的:防止佔用可卸載的文件系統。
1270 也可換成其餘目錄,只要該目錄穩定,不會被卸載(當時卸載的優盤目錄);
1271
1272 4.重設文件掩碼;
1273 umask()函數:
1274 目的: 防止繼承的文件建立屏蔽字拒絕某些權限;
1275 增長守護進程的靈活性;
1276
1277 5.關閉文件描述符
1278 繼承的打開不會用到,浪費系統資源,沒法卸載。
1279
1280 6.執行守護進程核心工做
1281
1282 7.設置守護進程退出。
1283
1284 "===信號========================================================================================================================"
1285
1286
1287 "===線程========================================================================================================================"
1288
1289 一。線程概念
1290 1.什麼是線程
1291 1)線程:LWP(light weight process):輕量級的進程,擁有獨立的PCB,共享進程地址空間,Linux下線程是最小的執行單位。
1292
1293 2.線程與進程的區別、聯繫
1294 進程獨享地址空間; 線程共享。
1295 進程是最小的分配資源單位; 線程是最小的執行單位。
1296 各自有獨立的PCB。
1297
1298 3.內核實現線程的原理:
1299 1.建立線程與建立進程相似;調用底層函數clone();
1300 2.有不一樣的PCB,但線程共享進程地址空間---》PCB各線程持有相同頁目錄---》三級映射一致。
1301 3.以每一個線程的LWP號, 做爲內核分配執行單位的依據。
1302 4.線程的ID != LWP;
1303 5.線程是寄存器與棧的集合。
1304
1305 3.線程之間共享、不共享那些東西
1306 共享:
1307 1)文件描述符; 2)信號的處理方式; 3)用戶ID和組ID;
1308 4)工做目錄位置; 5).text/.data/.bss/.ordata/heap-----》用戶空間(0-3G ,棧空間除外) ;
1309 不共享:
1310 1)線程ID; 2)用戶stack(棧空間); 3)內核stack(棧空間);
1311 4)信號屏蔽字; 5)errno變量; 6) 線程優先級
1312
1313 4.線程的優缺點
1314 優勢:
1315 1)線程間通訊能夠經過----全局變量 。(進程間不共享全局變量 --- mmap 映射)
1316 2)開銷小,節省空間
1317 3)程序的併發性提升。
1318
1319 缺點:
1320 1)第三方庫函數pthread,穩定性差;
1321 2)gdb調試工具支持很差。
1322 3)信號支持好(通常不要在線程中使用信號)。
1323
1324
1325 二。線程的控制原語:【重點】
1326 1.建立線程:
1327 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
1328 參數一: 傳出參數,建立的線程ID;
1329 參數二: 線程屬性,通常採用默認的(用 NULL)。
1330 參數三: 子線程的操做函數。
1331 參數四: 子線程操做函數的參數。
1332 返回值: 成功:0 ; 失敗:錯誤號;
1333
1334 2.獲取線程的ID
1335 pthread_t pthread_self(void);
1336 參數:無u;
1337 返回值: 成功:線程ID號。 失敗:無。
1338
1339 3.將當前線程退出:
1340 void pthread_exit(void *retval);
1341 參數一:線程退出值(void*類型); NULL:無退出值。
1342 返回值:無;
1343 對比:
1344 return : 返回到調用者那裏去;
1345 exit() : 進將當前進程退出;
1346 pthread_exit(); 將當前線程退出;
1347
1348 4.阻塞等待子線程退出,獲取退出狀態。
1349 int pthread_join(pthread_t thread, void** retval);
1350 參數一: 回收的線程ID;
1351 參數二: 被回收線程退出值。(NULL 表示不關心線程退出值)
1352 返回值: 成功:0; 失敗:錯誤號。
1353
1354 5.實現線程分離:
1355 int pthread_detach(pthread_t thread);
1356 參數一:待分離的線程ID;
1357 返回值:成功:0; 失敗:錯誤號。
1358
1359 6.殺死(取消)線程。
1360 int pthread_cancel(pthread_t thread);
1361 參數一:欲殺死的線程ID;
1362 返回值:成功:0; 失敗:錯誤號。
1363 注意:調用該函數時,欲殺死的線程必須調用系統調用函數(如:write,printf);以使線程進入內核,到達 記錄點/取消點。
1364 或者調用檢查函數(。。test)等會查一下;
1365 終止線程的方式:return;
1366 pthread_exit();
1367 pthread_cancel();
1368
1369 7.比較兩個線程
1370 int pthread_equal(pthread_t t1, pthread_t t2);
1371 參數1、二:比較的兩個線程ID號。
1372
1373 4.線程、進程控制原語對比;
1374 線程 進程
1375 pthread_creadte(); fork();
1376 pthread_self(); getpid()---getppid()---getpgid()---getsid();
1377 pthread_join(); wait()---waitpid();
1378 pthread_exit(); exit()----return;
1379 pthread_cancel(); kill();
1380 pthread_detach();---分離
1381 pthread_equal();----比較
1382
1383 三。NPTL
1384 pthread庫版本;
1385 查看:getconf GNU_LIBPATHREAD_VERSION
1386 gcc編譯指定 ---lpthread 選項。
1387
1388 四。線程的屬性【擴展】
1389 可在建立線程以前設置修改其默認屬性:
1390 pthread_attr_t 結構體內容:1)線程分離狀態; 2)線程棧空間大小; 3)線程警惕區大小; 4)線程棧低地址;。。。。。
1391
1392 1.屬性初始化
1393 pthread_attr_init();
1394 參數:attr:(傳出參數),待初始化的結構體。
1395 返回值:成功;0 ; 失敗:錯誤號;
1396
1397 2.銷燬自設屬性;
1398 pthread_attr_destroy(); 使用時機: 線程建立完畢。
1399
1400 3.線程分離狀態:
1401 1) int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 獲取線程分離狀態。
1402 參數一:attr:線程屬性結構體指針
1403 參數二:detachstate(傳出參數): PTHREAD_CREATE_DETACHED(分離);PTHREAD_CREATE_JOINABLE(分離);
1404 返回值:成功;0; 失敗:錯誤號;
1405 2)int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); 設置線程分離狀態。
1406
1407 4.線程棧地址:
1408 int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize); 獲取線程棧地址
1409 參數一:attr: 線程屬性結構體指針
1410 參數二:stackaddr:(傳出) 獲取線程棧地址
1411 參數三:stacksize:(傳出) 獲取線程棧大小。
1412 返回值:成功;0;失敗:錯誤號。
1413 int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr, size_t stacksize); 設置線程棧地址
1414
1415 5.線程棧大小
1416 int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);獲取線程棧大小
1417
1418 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 設置線程棧大小
1419 參數一:attr: 線程屬性結構體指針
1420 參數二:stacksize: 設置線程棧大小
1421 返回值:成功;0;失敗:錯誤號。
1422
1423
1424 五。線程使用注意事項
1425 1.退出線程應使用 pthread_exit();
1426 2.避免殭屍線程的產生:
1427 1)pthread_join(); 回收子線程。
1428 2)pthread_detach();分離線程。
1429 3)指定分離屬性,再pthread_create();建立線程。
1430 3.線程共享進程地址空間:malloc和mmap內存可被其餘線程釋放。
1431 4.多線程中應避免使用fork(),除非立刻exec;多線程fork()後,產生的進程中只含有調用fork函數的線程,其餘線程均退出。
1432 5.線程主函數中,應該避免返回局部變量地址值。
1433 6.避免多線程和信號混用。
1434
1435
1436
1437 "===線程同步、進程同步========================================================================================================================"
1438 一。同步、線程同步概念
1439 1.生活中的同步爲: 同時起步,協調一致。
1440 2.線程中的同步爲: 協同步調,指定訪問數據的前後順序。
1441 3.全部多個控制流,共同操做同一共享數據的場景,都須要同步機制。
1442 4.數據混亂的緣由:(產生與時間有關的錯誤)
1443 1)資源共享(獨享資源則不會)
1444 2)調度隨機
1445 3)線程間缺少必要的同步機制
1446 其中前二者不可改變,這是多線程併發得以實行的必要條件,那麼就須要在線程間加上同步機制。
1447
1448 二。線程同步的方法
1449 1.互斥量(互斥鎖:mutex)------》建議鎖(協同鎖)
1450 1)互斥量特徵
1451 1)建議鎖,不具備強制性。
1452 2)訪問共享數據前,加鎖,訪問結束後當即解鎖。
1453 3)線程不按規則訪問數據依然能夠成功(即不加鎖訪問);但數據會混亂。
1454
1455 2)一系列操做函數
1456 1)初始化互斥鎖
1457 1)動態初始化:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
1458 pthread_mutex_t 互斥鎖的類型,本質是一個結構體,只有 0 和 1 兩個值。
1459 參數一:互斥鎖,
1460 參數二:互斥鎖的類型(進行修改,能夠在進程間使用。)
1461 restrict:關鍵字;只用於限制指針:告訴編譯器,全部修改該指針指向內存中的操做,只能經過本指針完成;
1462 不能經過本指針以外的其餘變量和指針操做。
1463 2)靜態初始化:pthead_mutex_t muetx = PTHREAD_MUTEX_INITIALIZER;
1464
1465 2)加鎖:
1466 int pthread_mutex_lock(pthread_mutex_t *mutex);
1467 可理解爲將 mutex--;
1468 說明:嘗試加鎖,若是加鎖不成功,線程阻塞,阻塞到持有該互斥量的其餘線程解鎖爲止。
1469 3) 解鎖:
1470 int pthread_mutex_unlock(pthread_mutex_t *mutex);
1471 可理解爲將 mutex++;
1472 說明:主動解鎖,同時將阻塞在該鎖上的全部線程所有喚醒;至於哪一個線程先被喚醒,取決於優先級、調度。默認:先阻塞、先喚醒。
1473 4) 嘗試加鎖
1474 int pthread_mutex_trylock(pthread_mutex_t *mutex);
1475 說明: lock加鎖失敗會阻塞,等待所釋放; trylock:加鎖失敗直接返回錯誤號,不阻塞;
1476 5)銷燬互斥鎖
1477 int pthread_mutex_destroy(pthread_mutex_t *mutex);
1478 說明:程序結束時,要銷燬使用的互斥鎖。
1479 "在訪問共享資源前加鎖,訪問結束後當即解鎖,鎖的 粒度 越小越好。"
1480
1481 2.死鎖--------------------不是線程同步的一種方式,而是一種現象。
1482 1)死鎖一。(對同一個互斥量加鎖兩次。)
1483 連續加鎖,阻塞等待。
1484 示例:
1485 pthread_mutex_t mutex; //定義一個全局互斥鎖變量。
1486 void *do_sth(void* arg)
1487 {
1488 srand((unsigned int) time(NULL));
1489 while(1)
1490 {
1491 pthread_mutex_lock(&mutex); //子線程加鎖
1492 printf("hello ");
1493 sleep(rand()%3);
1494 printf("world\n");
1495 pthread_mutex_unlock(&mutex); //子線程解鎖
1496 }
1497
1498 pthread_exit(NULL); //結束子線程
1499 }
1500 int main(void)
1501 {
1502 pthread_t ptid;
1503 srand((unsigned int) time(NULL)); //隨機數的種子
1504 pthread_mutex_init(&mutex, NULL); //互斥鎖動態初始化
1505
1506 pthread_create(&ptid, NULL, do_sth, NULL); //建立子線程
1507 while(1)
1508 {
1509 pthread_mutex_lock(&mutex); //主控線程第一次對數據加鎖
1510
1511 printf("HELLO ");
1512 sleep(rand()%3); //這個睡眠額度做用是:即便此時CPU空出來,但因爲另外一個線程沒有拿到鎖,仍是沒法進行輸出。
1513 printf("WORLD\n");
1514 pthread_mutex_lock(&mutex); //死鎖:對同一互斥量連續加鎖兩次/屢次;形成線程阻塞。
1515 pthread_mutex_unlock(&mutex); //數據操做完後當即解鎖,使鎖的粒度最小。
1516 }
1517 pthread_mutex_destroy(&mutex); //程序結束,銷燬使用的互斥鎖。
1518 pthread_join(ptid, NULL); //回收子線程。
1519 pthread_exit(NULL); //主控線程退出
1520 }
1521
1522 2)死鎖二。(多個共享數據,多把鎖。持有鎖A的線程1請求鎖B,持有鎖B的線程2請求鎖A)
1523 更極端的狀況:震盪。
1524 解決方法: 1.當沒法獲取全部鎖的時候,放棄已經掌握的鎖
1525 2.規定 不一樣線程 獲取 共享數據 的順序(即規定獲取鎖的順序)。
1526
1527 //兩組共享的數據及其配套鎖
1528 typedef struct recond_m
1529 {
1530 int data_m;
1531 pthread_mutex_t mutex_m;
1532 }recond_m;
1533
1534 typedef struct recond_n
1535 {
1536 int data_n;
1537 pthread_mutex_t mutex_n;
1538 }recond_n;
1539
1540 recond_m data_1; //定義的兩個全局共享變量
1541 recond_n data_2;
1542 void *do_sth(void* arg) //子線程執行邏輯
1543 {
1544 srand((unsigned int) time(NULL)); //隨機數的種子
1545 while(1)
1546 {
1547 //加鎖順序: 先 data1, 再data2;
1548 pthread_mutex_lock(&data_1.mutex_m);
1549 data_1.data_m = 9; //對全局變量修改
1550 printf("zi xian data_m:%d\n ",data_1.data_m);
1551 pthread_mutex_lock(&data_2.mutex_n);
1552 data_2.data_n = 9;
1553 printf("zi xian data_n:%d\n ",data_2.data_n);
1554
1555 pthread_mutex_unlock(&data_2.mutex_n); //解鎖兩個共享數據
1556 pthread_mutex_unlock(&data_1.mutex_m);
1557 }
1558
1559 pthread_exit(NULL);
1560 }
1561
1562 int main(void)
1563 {
1564 pthread_t ptid;
1565 srand((unsigned int) time(NULL));
1566 //動態初始化兩把鎖
1567 pthread_mutex_init(&data_1.mutex_m, NULL);
1568 pthread_mutex_init(&data_2.mutex_n, NULL);
1569
1570 pthread_create(&ptid, NULL, do_sth, NULL); //建立子線程
1571 while(1)
1572 {
1573 //主控線程 : 先鎖 data2; 再鎖data1;
1574 pthread_mutex_lock(&data_2.mutex_n);
1575 data_2.data_n = 6;
1576 printf("zhu kong data_n:%d\n ",data_2.data_n);
1577 sleep(1); //空出CPU資源, 子線程加鎖。
1578 pthread_mutex_lock(&data_1.mutex_m);
1579 data_1.data_m = 9;
1580 printf("zhu kong data_m:%d\n ",data_1.data_m);
1581
1582 pthread_mutex_unlock(&data_1.mutex_m);
1583 pthread_mutex_unlock(&data_2.mutex_n);
1584
1585 }
1586
1587 pthread_mutex_destroy(&data_1.mutex_m);
1588 pthread_mutex_destroy(&data_2.mutex_n);
1589 pthread_join(ptid, NULL);
1590 pthread_exit(NULL);
1591 }
1592
1593 2.讀寫鎖(讀寫鎖只有一把)
1594 1)讀寫鎖特性
1595 1.寫獨佔,讀共享。
1596 2.寫鎖的優先級高於讀鎖。
1597 "詳解:三種狀況"
1598 1)寫模式加鎖:解鎖前,全部對該鎖加鎖的進程都會被阻塞。
1599 2)讀模式加鎖,解鎖前,若是其餘全部線程以讀模式加鎖會成功,以寫模式加鎖會失敗。
1600 3)讀模式加鎖,解鎖前,其它線程中既有寫模式加鎖,也有讀模式加鎖,全部線程阻塞;解鎖後,優先知足寫模式的加鎖。
1601
1602 2)一系列操做函數
1603 就不贅述了;和上述同樣。
1604 3)使用場景:
1605 適合於對數據結構讀的次數遠大於寫的次數。
1606
1607 3)讀寫鎖優勢:
1608 當讀線程 多於 寫線程時,能夠提升數據的訪問效率。
1609
1610 3.條件變量
1611 1)條件變量的特性
1612 1.條件變量自己不是鎖,可是依然能夠形成線程阻塞;一般與互斥鎖配合使用。
1613
1614 2)一系列操做函數(拿出其中的三個特殊函數)
1615 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
1616 說明:阻塞等待一個條件變量。隱喻着在此函數調用前,數據已完成加鎖操做;pthread_mutex_lock(&mutex)。
1617 該函數有三步:
1618 1)阻塞等待條件 cond 知足;
1619 2) 條件未知足時,解鎖已經得到的鎖。
1620 3)當條件知足時,被喚醒,接觸阻塞再次嘗試加鎖互斥量。爲一個原子操做。
1621
1622 int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
1623 說明:指定時間後嘗試調用該函數。符合條件則運行;不符合條件,不阻塞,返回錯誤號。
1624 參數三:絕對時間。
1625
1626 int pthread_cond_signal(pthread_cond_t *cond);
1627 喚醒至少一個阻塞在條件變量上的線程。(實際上也就只喚醒一個,可是man手冊中,沒有這樣寫)
1628 int pthread_cond_broadcast(pthread_cond_t *cond);
1629 喚醒所有阻塞在該條件變量上的線程。
1630
1631 3)生產者、消費者模型
1632 生產者線程:
1633 消費者線程:
1634 公共區(共享資源):
1635 對公共區添加條件變量,互斥鎖,對數據加以保護。
1636
1637 4)條件變量的優勢:
1638 相較於直接使用互斥量,使用它只有當條件知足時,各線程纔會競爭,提升了程序間的效率。
1639
1640 4.信號量 -------》本質:結構體。
1641 1)特性:
1642 1.進化版的互斥鎖。。(1-> N);
1643 "2.信號量的初值,決定了佔用信號量的線程的個數。 "
1644 2)一系列操做函數
1645 1)int sem_init(sem_t *sem, int pshared, unsigned int value);
1646 說明:初始化一個信號量
1647 參數一:信號量的指針。
1648 參數二:pshared 取0用於線程間,取非0 用於進程間.
1649 "參數三:信號量的初值。"
1650 2)int sem_destroy(sem_t *sem);
1651 說明:銷燬一個信號量
1652 3)int sem_wait(sem_t *sem); (類比pthread_mutex_lock());
1653 說明:信號量加鎖--。
1654 詳細:信號量大於0,則信號量--; 信號量等於0,則線程阻塞等待。
1655 4) int sem_post(sem_t *sem); (類比pthread_mutex_unlock());
1656 說明:信號量解鎖++;
1657 詳細:信號量小於最大值,則信號量++;信號量等於最大值,則線程阻塞等待。
1658 5)int sem_trywait(sem_t *sem);
1659 說明:信號量嘗試加鎖,不阻塞。
1660 6)int sem_timedwait(sem_t *sem, const struct timespec *abc_timeout);
1661 說明:指定時間後嘗試對信號量加鎖,成功則運行,不成功,返回錯誤號,不阻塞。
1662 參數二:絕對時間。
1663 例子:定時1秒; time_t cur = time(NULL); //獲取當前時間。
1664 struct timespec t_time; //定義結構體變量
1665 t_time.tv_sec = cur + 1; //定時1秒
1666 t_time.tv_nsec = 0;
1667 sem_timedwait(&sem, &t_time);
1668
1669 3)生產者、消費者模型
1670
1671 三。進程間同步
1672 1.信號量
1673 1.
1674 2.互斥量(mutex)
1675 1.進程間也可使用互斥鎖,來達到同步的目的。可是在初始化以前,應該修改一下其屬性。
1676 2.屬性修改函數:
1677 pthread_mutexattr_t mattr 類型; 用於定義mutex鎖的 屬性。
1678 int pthread_mutexattr_init(pthread_mutexattr_t *mattr) 函數; 初始化一個mutex屬性對象;
1679 int pthread_mutexattr_destroy(pthread_mutexattr_t *mattr) 函數; 銷燬mutex屬性對象,(非銷燬鎖);
1680 int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); 修改mutex屬性。
1681 參數二:pshared取值:
1682 線程鎖:PTHREAD_PROCESS_PRIVATE (mutex 的默認屬性即爲線性鎖,進程間私有)
1683 進程鎖:PTHREAD_PROCESS_SHARED
1684
1685 3.文件鎖
1686 int fcntl(int fildes, int cmd, ...);函數;
1687 參數一:文件描述符;
1688 參數二:
1689 F_SETLK(struct flock*) 設置文件鎖 (trylock);;
1690 F_SETLKW(struct flock*)設置文件鎖 (lock)W -->wait;
1691 F_GETLK(struct flock*) 獲取文件鎖 ;
1692
1693 參數三:struct flock 結構體內容;
1694 1)l_type: 鎖的類型: F_RDLCK(讀鎖); F_WRLCK(寫鎖); F_UNLCK(解鎖);
1695 2)l_whence:偏移位置:SEEK_SET; SEEK_CUR; SEEK_END;
1696 3) l_start: 起始偏移:
1697 4) l_len: 長度 ; 0 表示整個文件加鎖。
1698 5)l_pid; 持有該鎖的進程ID; 僅限F_GETLK中使用。
1699
1700
1701 "===線程========================================================================================================================"
1702
1703
1704 "===網絡編程========================================================================================================================"
1705
1706
1707 "===網絡編程之理論基礎========================================================================================================================"
1708
1709 一。協議概念
1710 1.協議:
1711
1712 2.典型協議:
1713 傳輸層: 常見協議:TCP / UDP;
1714 應用層: 常見協議:HTTP; FTP;
1715 網絡層: 常見協議:IP; ICMP; IGMP;
1716 網絡接口層:常見協議:ARP; RARP;
1717
1718 ARP協議:正向地址解析協議,經過已知的IP,尋找對應主機的MAC地址。
1719 RARP協議:反向地址轉換協議,經過MAC地址肯定IP地址。
1720 FTP :文件傳輸協議
1721 TCP :傳輸控制協議;是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。
1722 UDP:用戶控制協議,是OSI參考模型中一種無鏈接的傳輸層協議,提供面向事物的簡單不可靠信息傳送服務。
1723 IP:因特網互聯協議
1724 HTTP:超文本傳輸協議,是互聯網上應用最普遍的一種網絡協議。
1725 ICMP:Internet控制報文協議,是TCP/Ip協議族的一個子協議,用於IP主機和路由器之間傳遞消息。
1726 IGMP:Internet組管理協議,運行在主機和組播路由器之間。
1727
1728 二。B/S ; C/S 模型結構【即網絡應用層設計模式】
1729 1.C/S模型:(客戶機/服務器模式)
1730 如:實際應用:QQ;
1731 兩個數據端:客戶端(client)/服務器(server);
1732 該模型的優勢:
1733 1.緩存數據到本機,提升通訊效率。
1734 2.協議的選擇靈活。-------自定義協議,或者對現有協議進行裁剪。
1735 該模型的缺點:
1736 1.對用戶而言,安全性較低(由於在用戶端安裝了應用程序(即客戶端))。
1737 2.開發量大。
1738 3.受操做平臺限制。
1739 使用場景:
1740 1.當須要自定義協議
1741 2.對數據要求高。
1742
1743 2.B/S模型:(瀏覽器/服務器模式)
1744 藉助瀏覽器完成通訊,用戶不須要在主機上安裝應用程序。如(當年的偷菜遊戲,即網頁遊戲。)
1745 該模型的優勢:
1746 1.不受操做平臺限制;
1747 2.開發量小
1748
1749 該模型的缺點:
1750 1.由於數據不能緩存到本地,因此大型的網絡遊戲不能使用。
1751 2.協議選擇相對來講不太靈活。(瀏覽器的開發要求必須知足)。
1752
1753 使用場景:
1754 1.對數據要求不過高,
1755 2.跨平臺方便的
1756
1757
1758 三。分層模型"【重點, 必須掌握】"
1759 1.OSI 七層模型
1760 物數網傳會表應:【物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。】
1761
1762 2.TCP/IP 4層模型
1763 網網傳應:【網絡接口層(由物理層和數據鏈路層組成,也有人叫作數據鏈路層)、網絡層、傳輸層 、應用層】。
1764 4層模型與7層模型,互相對應。
1765 網絡接口層協議:ARP協議和RARP協議。 網絡層協議:IP協議、ICMP協議、IGMP協議。
1766 傳輸層協議:TCP/UDP協議(主要是這兩種); 應用層協議:HTTP協議、 FTP協議。
1767 TCP 是一種面向鏈接的、可靠的協議,有點像打電話。也就是說TCP傳輸的雙方首先要創建聯接,以後由TCP協議保證數據收發的可靠性,數據包丟失重發。
1768 UDP是無鏈接的傳輸協議,不保證可靠性,有點像寄信。使用UDP協議的應用程序須要本身完成丟包重發、消息排序等工做。
1769
1770 四。協議格式
1771 1.數據包的封裝【網絡環境中數據通訊過程】。
1772 1)(((((數據)應用層)傳輸層)網絡層)數據鏈路層);
1773 數據包裝完後,才能夠在網絡上進行傳輸;
1774
1775 2)傳輸層及其如下由內核控制,應用層由用戶控制。不一樣主機之間,數據在網絡中的發送,應用層數據經過協議棧發到網絡上時,每層協議都要加上一個數據首部,稱爲封裝。
1776
1777 2.以太網幀格式:
1778 ARP數據報格式; 藉助 IP----》獲取mac地址。
1779 目的地址,源地址,類型, 數據, CPC(校驗碼)。
1780 其中 源地址和目的地址是 網卡的硬件地址(即MAC地址),長度是48位;
1781
1782 2)以太網幀中數據長度最小爲46字節,最大爲1500字節。
1783
1784
1785 2.IP段格式
1786 4位首部長度, 4位版本號, 16位總長度, 8位TTL(記錄數據包的跳數), 32位源IP, 32位目的IP。
1787
1788
1789 3.TCP數據包格式:(面向鏈接的,複雜)
1790 16位源端口號, 16位目的端口號。 4位首部長度,6位標誌位; 16位窗口大小; 32位序號; 32位確認序號。
1791
1792 4.UDP數據包格式 (無鏈接的)
1793 16位源端口號; 16位目的端口號。 最大包括:2^16 = 65535;
1794 端口號:在一臺主機上惟一標識一個進程。 != pid; 應用與網絡
1795 IP地址:在網絡中惟一標識一臺主機。
1796 IP地址+端口號; 在網絡環境中惟一標識一個進程。------》socket
1797
1798 HTTP 服務默認 TCP 協議的 80 端口;
1799 FTP 服務默認 TCP協議的 21 端口;
1800 TFTP 協議默認 TCP協議的 69 端口。
1801
1802 5.NET映射機制:映射表
1803 1.私有IP:僅在局域網有效。 (容許重複)
1804 2.公網IP:在整個網絡環境可見。 (不容許重複,即衝突)
1805 3.路由器內部,NAT映射表。藉助私有IP和端口號 -------- 共有IP和標號。
1806
1807 6.打洞機制:
1808 藉助 公網服務器, 將兩臺私有IP的主機,直接相連,完成數據的直接傳遞。
1809
1810 五。TCP 的3次握手創建鏈接、4次握手斷開鏈接。"【重點】"
1811 三次握手創建鏈接:
1812 主動發起鏈接一方,發送請求:SYN(請求創建鏈接);
1813 被動接受連接一方,回覆:ACK(應答),SYN();
1814 主動發起連接一方,回覆:ACK(應答,創建鏈接成功);
1815
1816 四次握手斷開鏈接:
1817 主動關閉鏈接一方1: FIN
1818 被動關閉鏈接一方1: ACK
1819 主動關閉鏈接一方2: FIN
1820 被動關閉鏈接一方2: ACK
1821
1822 mss(最大報文長度): 與下面的MTU大小相關。
1823
1824 六。MTU概念
1825 MTU:最大傳輸單元。
1826 在以太網幀格式中爲 1500 字節。
1827 (MTU - 數據報頭)= mss ;
1828
1829 七。滑動窗口
1830 給對端提供一個發送數據的總上限值。---------》進行流量控制
1831 最大:65535;由於:在報頭中佔據16位。
1832
1833 八:TCP協議格式:
1834 16位源端口, 16位目的端口,32位序列號, 32位確認序列號, 16位窗口大小, 標誌位(SYN, ACK, FIN);
1835 須要記住使用的就上面這些;
1836
1837 九。TCP狀態轉換圖:"【重點】"
1838
1839
1840
1841 十:2MSL
1842 1)查看:net
1843
1844
1845 十一。端口複用:
1846
1847 十二:半關閉:
1848 1)主動關閉連接一方,處於FIN_WAIT_2. 4次握手---完成兩次。
1849 2)
1850 "===UDP======================================"
1851 1.UDP 協議格式
1852 主要針對不穩定的網絡層,作傳輸行爲。 TCP--徹底彌補 97% ;UDP---徹底不彌補。
1853 TCP 和UDP 優缺點:
1854 網絡中TCP一次傳輸的多組數據路徑是相同的(若是網絡中的路由器沒有發生變化);
1855 網絡中UDP一次傳輸的多組數據路徑是不一樣的(致使:)。
1856
1857 TCP:面向鏈接的可靠數據傳輸。---類比打電話
1858 優勢: 1.數據傳輸可靠;;
1859 2.穩定:數據內容穩定,流量穩定(mss, 滑動窗口),速率穩定(即線路穩定,在網絡中通過相同的路由)。
1860 缺點: 1.效率低,開銷大。
1861 2.速度慢,(由於每次數據傳輸過去,須要對方回覆)
1862
1863 應用場景:重要文件、大文件。
1864
1865 UDP:無鏈接的不可靠報文傳遞。-----類比發短信
1866 優勢: 1.速度快
1867 2.實時性高,效率高。
1868 缺點: 1.數據傳輸不可靠。
1869 2.穩定性差(每次傳輸的路徑不同)。
1870
1871 應用場景:對實時性要求較高:視頻聊天、視頻電話、分屏廣播。
1872
1873 騰訊:開始:TCP ---後來TCP+UDP(作判斷,看適合用哪一種);----後來UDP+應用層校驗(不丟失數據包)--(這種方式須要自行開發應用層協議。)
1874
1875 2.UDP C/S 服務器模型
1876 比較差別
1877 TCP: 三次握手創建鏈接---socket();bind(); accept();read();小寫轉大寫;write();-----service端
1878 -------socket(); connect();write(); read();
1879 UDP: 無需創建連接---socket(); bind(); recvfrom();
1880
1881 UDP默認狀況下支持 多路IO---高併發服務器。
1882 1.爲了使支持狀況更好,須要應用層本身封裝校驗;
1883 2.擴大接收端緩存區大小。使用 setsockopt();
1884
1885 注意:send(), recv() 只能用於TCP連接的C/S模型。
1886
1887 3.UDP 廣播
1888
1889 4.UDP 組播
1890
1891 "上課所用的分屏軟件的設計思想:"
1892 server端:
1893 1)服務器端:截屏模塊,截取本地屏幕數據。獲得圖片,(保證人眼的觀看,須要1秒24幀)幾M。
1894 2)降幀12幀;保證數據發送效率。
1895 3)選用適當的算法進行壓縮。 幾十KB
1896 4)爲進一步提升效率,只將有變化、改動、座標區域,截取,壓縮,發送。
1897
1898 client端:
1899 1)每臺接收的主機 有個客戶端,使用和服務器端相同的端口。
1900 2)接收到數據後以相同的算法,逆方式解壓縮。
1901
1902 5.本地套接字:
1903 IPC的一種方法:
1904
1905 6.經常使用的開源庫(網絡編程)
1906 1.libevent
1907 2.libv
1908 7.服務器壓力測試開源庫
1909
1910 8.使用軟件:
1911 wareshark;
1912
1913 "===UDP======================================"
1914
1915
1916
1917
1918 "===網絡編程之理論基礎========================================================================================================================"
1919
1920
1921 "===網絡編程之 socket(套接字) 編程========================================================================================================================"
1922 在網絡通訊中,socket通訊時必定是成對出現的。
1923 使用的時候必需要指定:IP和端口號 ;socket = IP+port(端口號);
1924
1925 一。理論基礎:
1926 1.網絡字節序
1927 大端法:高位存低地址。
1928 小端法:高存高。(x86結構,即我的電腦;微軟的主推)
1929
1930 網絡環境中:--------》網絡字節序:大端法。
1931 本地環境中:--------》本機字節序:小端法。
1932 因此網絡中傳輸的數據須要進行字節序轉換。
1933 "一套操做函數:";
1934 uint32_t htonl(uint32_t hostlong); ----本地--轉--網絡-- 32; --->IP 地址
1935
1936 uint16_t htons(uint16_t hostshort); ----本地--轉--網絡-- 16; --->port號(端口號)
1937
1938 uint32_t ntohl(uint32_t netlong); ----網絡--轉--本地--32;
1939
1940 uint16_t ntohs(uint16_t netshort);----網絡--轉--本地--16;
1941
1942 2.IP地址轉換
1943 由於本地的IP地址爲字符串型,適合人類查看。
1944 網絡上的IP爲 unsigned int 型。
1945 str IP <-----> 網絡字節序IP
1946 int inet_pton(int af, const char *src, void *det );
1947 af: ipv4:AF_INET;
1948 ipv6:AF_INET6;
1949
1950 src: 網路字節序的IP地址;
1951
1952 det: 用來儲存轉化後的IP地址。
1953
1954
1955 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
1956
1957 af: ipv4: AF_INET;
1958
1959 ipv6: AF_INET6;
1960
1961 src:網絡字節序的IP地址。
1962
1963 dst:用來存儲轉化後的IP地址。
1964
1965 size: dst的大小。
1966
1967
1968 3.socketaddr地址結構
1969 定義變量: struct sockaddr_in saddr;
1970
1971 初始化:
1972
1973 struct sockaddr_in {
1974 sa_family_t sin_family; /* address family: AF_INET */
1975 in_port_t sin_port; /* port in network byte order */
1976 struct in_addr sin_addr; /* internet address */
1977 };
1978
1979 二。C/S模型實現的 TCP 客戶端服務器程序"【重點, 必須掌握】"
1980 socket----套接字:
1981 本質:內核緩衝區(發送,接收。)
1982 "進行通訊的時候,是成對出現的。雙向全雙工"
1983
1984 1.建立一個套接字:
1985 SOCK_DGRAM --------報式協議 UDP 協議
1986 protocol:0 流式默認: TCP
1987 報式默認: UDP
1988 返回值:成功則指向新建立的socket的文件描述符; 失敗:返回-1,設置errno.
1989
1990 2.int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);綁定服務器的:IP, port(端口號);到套接字上。
1991 參一:sockfd :socket文件描述符。
1992 參二:構造出IP地址+端口號;(sockaddr_in 類型)
1993 參三:地址的長度。
1994
1995 3. int listen(int sockfd, int backlog); 設置同時向服務器發起三次鏈接的客戶端數量(注意:不是客戶端連接服務器的數量) -- 10 ;
1996 參一:socket函數的返回值(即socket文件描述符)
1997 參二:數量上限。
1998 注意:這個函數的做用是:指定鏈接數的,而不是等待客戶端鏈接的。
1999
2000 4.int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 阻塞等待客戶端發起鏈接請求。
2001 參一:socket函數的返回值(即socket文件描述符)
2002 參二:addr:傳出參數。返回客戶端的地址結構(IP、port)。
2003 參三:addrlen:傳入、傳出參數。
2004 返回值:返回一個新的fd,指向客戶端的套接字。
2005
2006 5.int connect(int sockfd, const struct aockaddr *addr, socklen_t addrlen);
2007 參一:socket函數的返回值(即socket文件描述符)
2008 參二:傳入參數,指定服務器端地址信息,含IP地址和端口號。
2009 參三:傳入參數:地址的大小。
2010 返回值:成功;0;失敗:-1。
2011
2012
2013 三。服務器、客戶端封裝錯誤處理模塊。
2014
2015 封裝思想:
2016 將系統調用進行 淺封裝;
2017 簡化程序邏輯 ------首字母大寫-------能夠直接從代碼編寫頁面進入 man page。
2018
2019
2020 read返回值:
2021
2022 > 0: 返回實際讀到的字節數
2023
2024 == 0: 到達文件末尾。或者管道對端關閉。或者套接字對端關閉。
2025
2026 < 0 (-1):
2027
2028 1. errno == EINTR ( ECONNABORTED 網絡中)
2029
2030 慢速系統調用,被信號中斷。 應該設置重啓。
2031
2032 2. errno == EAGIAN (或 EWOULDBLOCKED)
2033
2034 待讀對象設置非阻塞讀,而且此刻沒有數據到達。 應該設置從新讀取。
2035
2036 3. error
2037 perror(); exit();
2038 readn
2039
2040 readline
2041
2042
2043 四。多進程併發服務器
2044 1. 流程: socket() bind() listen() accept() read () write() close();
2045 詳解: 1.建立套接字; 2.定義地址變量,給他賦值IP、port; 3.監聽客戶端鏈接請求。 4.在循環阻塞等待連接客戶端,一旦有客戶端鏈接成功,就建立子進程。
2046 5.子進程負責與客戶端通訊; 6.父進程 繼續阻塞等待客戶端的連接; 同時註冊信號,回收子進程。
2047
2048 2. 子進程用來跟客戶端通訊。―― fork()
2049
2050 3. 父進程。 監聽客戶端鏈接請求。 註冊信號捕捉函數,回收子進程。
2051
2052 4. while (1 ) {
2053
2054 fd = accept()
2055
2056 fork();
2057 }
2058
2059
2060
2061 五。多線程併發服務器
2062
2063 1. socket() bind() listen() accept() read () write() close();
2064 詳解:1.建立套接字; 2.定義地址變量,給他賦值IP、port; 3。監聽客戶端鏈接請求; 4.在循環中,主控線程阻塞等待客戶端的連接,一旦有客戶端鏈接成功,就建立子線程,同時分離或專門用一個子線程回收剩餘的子線程。
2065 5.主控線程負責 繼續阻塞等待客戶端鏈接, 6.子線程負責與客戶端通訊。
2066
2067 2. 子線程用來跟客戶端通訊。―― pthread_create();
2068
2069 3. 主線程。 監聽客戶端鏈接請求。 子線程1 :pthread_join(); pthread_detach();---修改線程。
2070
2071 4. 客戶端通訊---小寫--大寫: 子線程的主控函數。
2072
2073 六:多路I/O轉接
2074
2075 1.select【*】
2076 1)一組函數
2077
2078 2)監聽、轉換,實現方法、思想
2079
2080 3)創建流程: socket() setsockopt() bing() listen() fd_set集合的賦值 select() FD_ISSET()
2081 accept() 符合條件的描述符通訊。
2082
2083 2.poll
2084 1)一組函數
2085 2)監聽、轉換,實現方法、思想
2086 3)區別poll、select比較,優缺點;
2087
2088 3.epoll【**】
2089 1)一組函數
2090 2)監聽、轉換,實現方法、思想
2091 3)區別poll、select、epoll比較,優缺點;;
2092
2093 七。epoll多路IO轉接模型
2094 1.設置突破1024文件描述符限制
2095 2.epoll操做函數
2096 epoll_create();
2097 epoll_ctl();
2098 epoll_wait();
2099 3.epoll實現多路IO轉接模型;
2100 八.epoll
2101
2102
2103 "===網絡編程之 socket 編程========================================================================================================================"
2104
2105
2106 "===網絡編程