原文:http://blog.csdn.net/ye_wei_yang/article/details/52777499html
1、Linux的磁盤分區及目錄linux
Linux的配置是經過修改配置文件來完成。程序員
1.一、Linux磁盤分區shell
Linux能夠將磁盤分爲多個分區,每一個分區能夠被當作一個獨立的磁盤使用,磁盤類型:主分區、擴展分區、邏輯分區。編程
主分區標記爲活動,用於操做系統的引導,一塊磁盤最多劃分4個主分區,主分區存放操做系統的文件或用戶數據。ubuntu
擴展分區:主分區小於4個時才能夠劃分擴展分區,一塊磁盤最多有一個擴展分區,擴展分區不能保存任何數據,必須在擴展分區中進一步劃分邏輯分區,用戶數據只能保存在邏輯分區中。vim
邏輯分區:擴展分區中能夠創建多個邏輯分區。windows
Linux中大多數硬件都是以文件的方式進行管理,這些硬件設備被映射到"/dev"目錄下對應的文件中,在‘/dev’目錄下每一個磁盤分區映射爲一個文件,這些文件採用字母加數據的形式,如:數組
/dev/xxyN瀏覽器
其中的xx表示區名所在磁盤的設備類型,通常hd表明IDE接口的磁盤,sd表明SCSI或SATA便可的磁盤(光盤驅動器及U盤),fd表明軟盤驅動器,tty是一種字符型的終端設備ttySn是串口設備。「y」表示分區所在的磁盤是當前接口的第幾個設備好比第一個SCSI硬盤就是「/dev/sda」,第二個SCSI硬盤就是「/dev/sdb」。「N」表示分區的序號,前四個分區(主分區或擴展分區)使用1-4表示,邏輯分區從5開始。
分區完成後,用戶並不能直接使用這些分區,須要格式化後再經過 mount命令掛載後才能使用,如使用mount命令將「/dev/sdb2」掛載到「/mnt/disk」目錄,全部保存到/mnt/disk目錄下的數據就會被保存到/dev/sdb2分區中。
1.二、Linux文件系統及目錄結構
文件系統是一種存儲和組織計算機文件及數據的方法,文件系統一般使用硬盤和光盤的存儲設備,並維護設備中的物理位置。
Linux操做系統默認操做FAT、FAT32兩種文件系統,默認狀況下不支持NTFS系統,推薦使用ext3(第三版的擴展文件系統)文件系統。ext3是一種日誌文件系統,在對系統數據進行寫操做前,會把寫操做內容寫入一個日誌文件中,一旦操做被意外停止,系統可以在從新啓動時根據日誌完成該寫操做。
Linux文件系統中,文件是存儲信息的基本結構。文件、目錄、硬件設備都以文件的形式表示,文件名能夠由字符、數據、原點、下劃線組成,長度不超過256個字符。Linux中經過圓點區分文件名和擴展名幫助用戶區分文件類型,用戶能夠根據本身須要隨意假如本身的擴展名。Linux中有4種文件類型:普通文件,如文本文件、圖片文件、視頻文件、shell腳本文件;目錄文件:特殊的文件;連接文件;特殊文件;
文件系統採用樹形的結構。
Linux中每一個用戶有個家目錄,若是是管理員(root用戶)家目錄是/root,如果普通用戶家目錄是/home。路徑,從一個目錄到另外一個目錄或文件的道路被稱爲路徑,「.」表示當前目錄,「..」當前目錄的父目錄,「~」當前用戶的家目錄,「-」上一個目錄。
2、經常使用命令
poweroff:關閉系統 reboot:重啓計算機 clear:清除終端顯示 pwd :顯示當前目錄 cd:改變當前目錄 . :表示當前目錄 .. : 表示當前目錄的父目錄 ~「」表示home目錄
- 上一個工做目錄
mv :移動命令 cp:複製命令 rm:刪除命令 mount:掛載命令 chamod:改變權限命令
cat:打印命令 mkdir:新建文件夾 lsmod:查詢設備
netstate -nl :查看網絡狀態 netstate -nlu :查看UDP狀態
ifconfig 查看網絡配置 ifconfig -a:全部的網卡 ifconfig eth0 up/down 打開或關閉eth0設備 ifconfig 能夠用來配置IP和網絡掩碼。 ping:查看網絡是否通 date:查詢時間 date -s :修改系統時間 cal:日曆
man 命令:查看命令的使用方法。 kill 進程號:結束一個進程
2.一、vim命令
命令模式,啓動後默認處於該模式,其餘模式用ESC鍵或者Ctrl+C切換到命令模式。
插入模式,和txt文檔編輯同樣編輯,在命令模式下用i、o、a命令進入該模式。
可視模式,該模式下可用方向鍵進行內容選擇,而後進行復制、粘貼和其餘操做,在命令模式下使用v進入該 模式。
塊操做模式,該模式下可用方向鍵進行內容選擇,選擇時可模擬鼠標選擇的方式。在命令模式下使用ctrl+v進入該模式
修改模式,該模式下,相似於其餘軟件用insert鍵來完成切換。命令模式下用R進入該模式。
擴展命令模式,該模式下能夠執行一些擴展命令。命令模式下使用‘:’進入該模式。
vim幾種操做選擇:「o」 能夠只讀方式打開該文件,「e」可正常編輯,使用該方式注意肯定其餘用戶沒有正在編 輯這個文件,「r」從臨時交換文件中回覆,「q」退出編輯該文件,「a」放棄並同時撤銷後續命令的執行,「d」刪除臨時交換文件。
文件編輯完成,但願關閉須要首先切換到命令模式,擊中退出方式::q 直接退出,:q!強行退出,若是文件內容發生改變則不保存,:wq保存並退出,:wq!強行保存並退出,通常用於文件是隻讀的狀況下,可是文件的擁有者是當前用戶。
2.二、Vim經常使用的操做鍵
命令模式經常使用的操做鍵:
G:移動到文件的最後一行
nG:n爲數字,移動到文件的第n行。
/word: 向下查找關鍵字word
?word: 向上查找關鍵字word
n:重複前一個查找
N:反覆重複前一個查找
:n,$s/a/b: 替換第n行開始到最後一行中每一行的第一個a爲b。
:n$s/a/b/g: 替換第h開始到最後一行每一行全部的a爲b,n位數字,若n爲.表示從當前行開始到最後一行
d$: 刪除光標所在位置到該行最後一個字符。
dd: 剪切當前行。
yy: 複製所選內容
nyy: 複製從光標開始n行內容
p: 將已經複製的內容粘貼到光標下一行。
P: 將已經複製的內容粘貼奧光標上一行。
u: 復原上一個操做。
ctrl+R: 重複前一個操做。
o: 當前下插入空行,並進入插入模式。
O: 當前下插入空行,並進入插入模式。
. : 重複前一個動做。
i : 進入插入模式,從當前光標所在位置插入。
I : 插入模式,從當前行第一個非空格處插入。
r : 插入模式,替換光標所在字符。
R: 進入修改模式。
ESC鍵:返回命令模式。
(2) 擴展命令模式經常使用操做鍵
:w ---- 保存。
:w! ---- 文件爲只讀時強制保存,不過可否保存還要看文件的權限。
:q ---- 離開vim。
:q! ----- 強制退出。
:wq ------- 保存後離開。
:x ------ 保存後離開。
:w[文件名] ----- 另存爲新文件。
v ---------- 進入可視模式。
ctrl+V ------ 進入塊操做模式。
:r[文件名] ----- 將文件名的文件讀到光標後面。
n1,n2 w[文件名] ----- 將n1到n2另存爲新文件
:new ----- 新增水平窗口
:new filename --- 新增水平窗口,並在新增的窗口加載filename文件。
:v new ----- 新增垂直窗口。
:v filename ----- 新增垂直窗口,並在新增窗口加載filename文件。
ctrl+W+方向鍵 ---- 切換窗口。
:only ---- 緊保留目前的窗口。
:set nu ----- 顯示行號
:set nonu ---- 不顯示行號
:set readonly ----- 文件只讀,除非使用!可寫。
:set ic ---- 查找是忽略大小寫。
:set noic ---- 查找時不忽略大小寫。
3、桌面環境
Linux的桌面圖形界面有不少種,GNOME KDE Fluxbox Xfce FVWM sawflish WindowMaker等,最經常使用的是GNOME和KDE兩種。
3.一、遠程管理
Telnet協議是Internet遠程登陸服務的標準協議,提供了在本地計算機上完成遠程主機工做的能力,用戶能夠在Telnet程序中輸入命令,這些命令會在遠程服務器上運行。傳統的Telnet安全性差,許多服務器會將Telnet服務關閉,使用更安全的SSH。
ubuntu 開啓Telnet服務步驟, http://www.linuxdiyf.com/linux/17355.html
SSH是Secure Shell 的縮寫,爲創建在應用層和傳輸層上的安全協議,SSh對所傳數據進行加密保證了數據的安全並且數據是通過壓縮的提升了傳輸速度。SSH能夠代替Telnet,又能夠爲TFP、POP提供一個安全通道。
Linux及windows客戶端經過SSH連接到服務器的方法:
(1) Linux客戶端
Linux客戶訪問SSH服務器經過如下幾個命令完成:
① ssh [-CflRv] [用戶名@] SSH服務器 [命令] ,
SSH服務器指定要連接的服務器,能夠使用FQDN或IP地址。
用戶名@:指定連接SSH服務器的用戶名,不指定用戶時默認以root用戶連接。
命令:使用ssh命令能夠連接到服務器,有時須要在SSH服務器上執行一個命令時,能夠直接經過此 參數指定須要執行的命令。
-C:啓用壓縮功能
-f: 在詢問密碼以後且在執行[命令]以前,將ssh轉到後臺運行。
-L:將本地系統中的某個端口轉發到遠程系統。
-R: 將遠程系統 的某個端口轉發到本地端口
-v: 顯示與鏈接和傳送有關的調試信息。
例如: ssh 192.168.159.11 經過ssh鏈接到遠程計算機,默認使用root用戶。若是是第一次鏈接到遠 程計算機,本地主機的用戶須要生成鏈接遠程主機的RSA公鑰,在此出現的警告輸入yes。退出遠程 鏈接服務器,輸入exit。
② SCP命令能夠使用SSH的方式在遠程主機和本地主機複製文件或目錄,語法以下,
scp [-Cpqrv] [[用戶名@]複製源主機:]複製源文件[[用戶名@]複製目標主機:][複製目標文件]
若是是windows客戶端,能夠用putty。
(2) RDP
在Windows中可經過「遠程桌面」功能鏈接到遠程的計算機進行管理。
4、Linux命令基礎
4.一、Linux命令分類
Linux操做系統中,命令分爲兩種:Shell內部命令、Shell外部命令。
Shell內部命令:shell內部命令是一些較爲簡單的又經常使用的命令,如cd、mkdir、rm等,這些命令在shell啓動時載入內存。
Shell外部命令:Linux中大多數命令屬於外部命令,每個shell外部命令都一個獨立的可執行程序,也就是shell的外部命令是一些實用工具程序,管理員能夠獨立的在shell環境下安裝或卸載這些shell外部命令。
Linux的內部命令能夠在任何目錄任什麼時候間執行,而外部命令在執行時,Linux必須找到對應的可執行程序。Shell中一個名爲PATH的環境變量,該變量包括一些路徑用於shell自動搜索。
cat /etc/shells 來查看系統中的shell種類。
Shell中的引號分爲三種:單引號,雙引號,反引號
由單引號引發來的符號都做爲普通字符出現。特殊字符用單引號引發來後,失去原來的意義,變爲普通字符解釋。
雙引號的做用與單引號相似,區別在於沒那麼嚴格,單引號忽略全部的特殊字符,雙引號中的3中特殊字符不被忽略 $ \ '。
反引號· 位於鍵盤的左上角,被反引號引發來的被shell解釋爲 命令行
用#作註釋。
4.二、Linux命令格式
Shell解釋器在用戶和內核之間至關於一個翻譯的角色,負責解釋用戶輸入的命令。shell是操做系統和用戶進行交互的界面。命令的基本格式:
命令 [選項] [參數]
命令是須要執行的操做,選項是對命令的要求,參數用於描述命令的做用對象。好比 ls -l /root ,命令是ls,選項-l表示要以長格式顯示文件信息,/root 是 ls的命令參數,表示ls命令做用的對象是 /root目錄。
5、Linux的目錄及文件管理
5.一、Linux的主要目錄
/ :根目錄,一臺計算機只有一個根目錄,全部內容都是從跟目錄開始。如/etc ,先從根目錄開始在進入etc目錄
/root:系統管理員的家目錄。
/bin:存放了標準的Linux工具,如ls、cp、rm等。該目錄已經包含在PATH中,使用該目錄程序無需使用路徑
/boot:用於加載程序的文件。
/proc:操做系統運行時,進程信息及內核信息,若是CPU、硬盤分區、內存信息等存放在該目錄。
/etc:存放系統的配置方面的文件,如在系統安裝vsftpd這個軟件,你想要修改vstpd配置文件的時候,vstpd的配置文件就在/etc/vstpd目錄下。
/etc/init.d 存放系統或以system V模式啓動的服務腳本。
/etc/xinetd.d: 若是服務是經過xinetd模式運行的,服務的腳本要放在這個目錄下。
/etc/rc.d : 存放BSD方式啓動腳本,如定義網卡開啓腳本等。
/etc/X11:存放X-Windows相關的配置文件
/dev :主要存放與設備(包括外設)有關的文件。
/home :存放每一個用戶的家目錄。每一個用戶的設置文件,桌面文件夾、用戶數據都放在這裏。
/tmp :臨時目錄。
/bin、/usr/bin:大部分系統命令都是二進制文件形式保存。通常用戶使用的命令都在這兩個目錄,系統核心命令工具,如cd、ls、cp、等都在/bin目錄。如Web瀏覽器爲於/usr/bin目錄,能夠與其餘用戶共享使用。
/sbin、/usr/sbin :存放root用戶的命令文件。
/usr/local :用於存放手動安裝的軟件。
/usr/share:存放系統共用的文件。
/usr/src:存放內核源碼的目錄。
/var :存放一些常常變化的文件。
/var/log:存放系統的日誌。
/opt:存放那些可選的程序。
/lib:系統的庫文件
/lost+found:在文件系統中,系統意外崩潰或意外關機時,產生的一些文件碎片放在該目錄。
/mnt : 存放掛在存儲設備的掛載目錄。
/meia:有些發行版使用這個目錄來掛載那些USB接口的移動硬盤,CD/DVD驅動器等。
5.2目錄結構及操做命令
Linux系統中,以.開頭的文件名錶示該文件是隱藏文件, ls命令用於顯示指定目錄的內容,語法:
ls [-anruhtFS1R] --time=<atime|ctime> --color<=使用時機> [目錄...]
[目錄...]:指定要顯示內容的目錄或目錄縮寫,若是須要顯示多個目錄,可在目錄名之間使用空格
-a:顯示包括影藏文件在內的全部文件及目錄。
-n:使用UID和GID代替用戶名顯示文件或目錄全部者和擁有者。
-r:反向排序。
-u:以最後存取時間排序,顯示文件和目錄。
-h:使用k、M、G爲單位,提升信息可讀性。
-t:根據文件和目錄最後修改時間的順序顯示文件和目錄。
mkdir 建立目錄,語法以下
mkdir [-p] [-m<目錄屬性>] 目錄名稱...
目錄名稱:須要建立的目錄,若需創建多個目錄,可在目錄名之間使用空格分隔。
-p:若是要創建的目錄父目錄沒建立,則一塊兒創建父級目錄。
-m:創建目錄時,同時設置目錄權限,權限設置方法與chmod命令相同。
5.三、文件操做命令
創建目錄是爲了有效分類管理文件。
touch:改變文件或目錄時間
file:識別文件類型。 Linux系統文件的擴展名只是爲了方便使用者識別文件類型,對系統自己沒有任何意義。file命令能夠識別文件類型,語法以下
file [-bcLz] {-f<文件名>}文件|目錄
cp:複製文件或目錄。將目錄或文件複製到另外一個目錄,語法以下:
cp [-abdfilprsuv] [-S<備份字符串>] 源文件或目錄 目標文件或目錄
rm:刪除文件或目錄,語法以下:
rm [-filrv] 文件或目錄
mv:移動或改名現有的文件或目錄
mv [-fiub] [-S<備份字符串>] 源目錄或文件 目標目錄或文件
ln:連接文件或目錄,語法以下:
ln [-bdfis] [-S<備份字符串>] 源文件或目錄 [連接文件]
locate:查找文件或目錄,語法以下
locate 查找內容
該命令只會在保存文件和目錄名稱的數據苦衷查找。查找內容使用*表示任意字符,?表示任何一個字符。例如tony*zhang ,locate命令會查找以tony開始以zhang結尾的文件或目錄。
which:查找文件,語法以下:
which [文件]
該命令只會在PATH環境變量中定義的 路徑及命令別名中查找。
whereis:查找文件,語法以下:
whereis [-bu] [-B<目錄>] [-M<目錄>] [-S<目錄>] [文件...]
find :查找文件或目錄
gzip:壓縮文件,語法以下:
gzip [-cdf1Nnqtvr] [-壓縮比] [--bast|--fast] [-S<壓縮字尾字符串>] 要壓縮的文件
bzip2:壓縮文件,語法以下:
bzip2 [-cdfktvz] [-壓縮比] 要壓縮的文件
tar:壓縮備份,能夠將多個文件合併爲一個文件,打包後文件的擴展名爲.tar,默認狀況下不壓縮tar文件,能夠經過選項在打包同時進行壓縮。
zip/uzip:ZIP文件壓縮與解壓。
不一樣文件的壓縮和解壓縮:
.zip
解壓:unzip filename.zip
壓縮:zip filename.zip dirname
.rar
解壓:rar -x filename,rar
壓縮:rar -a filename.rar dirname
.tar.gz或tgz
解壓:tar -zxvf filename.tar.gz
壓縮:tar -zcvf
5.四、文本查看命令
cat:顯示文件內容,語法以下
cat [-bEsT] [文件..]
head:顯示文件內容的最前部分。如法以下:
head [-qv] [-c<顯示數目>] [-[n]<顯示行數>] [文件...]
tail:顯示文件內容的末尾部分
tail [-fqv] [-c<顯示數目>] [-[n]<顯示行數>][文件..]
more :逐頁顯示文件內容
grep 查找並顯示符合條件的內容,語法以下:
grep [-aciInqvwxE][-顯示行數][-e<範本樣式>][-f<範本樣式>][-d<進行操做>][範本樣式][文件或目錄]
6、用戶及組管理方式
用戶組有兩種:初始組、額外組。每一個用戶必須屬於一個初始組,能夠同時加入多個額外組。Linux將每一個用戶看作一個32位的整數,這個整數就是UID。Linux內部運做大部分都是使用UID,給人看時纔會把UID轉換爲用戶名。有三種用戶類型:通常用戶、超級用戶(root)、系統用戶。
每一個用戶對應一個UID,每一個組對應一個UID,創建用戶時默認創建一個與用戶名相同名稱的組,組的GID和用戶UID相同。
Linux中全部信息都是經過配置文件的方式保存,用戶及組也是。
7、軟件的安裝及管理
7.一、常見軟件安裝方式
綠色軟件:無需安裝直接能夠使用。
提供安裝程序的軟件包:在軟件包內提供了install.sh、setup.sh等安裝程序或以.bin格式單個執行文件提供 deb方式:deb是Debian軟件格式包,文件擴展名.deb,經gzip和tar打包而成,處理這些包的經典程序是dpkg,經過apt來運行。
RPM格式:RPM是在Linux洗普遍使用的軟件管理器,RPM僅適用於安裝用RPM來打包的軟件。
源碼方式:使用源碼本身經過本身編譯生成二進制文件的軟件安裝方式。
8、Shell腳本
bash Shell 支持在交互模式中一次提交多個命令執行,有三種方法:使用分號隔開、&& 條件隔開,只有前一個命令成功執行時才執行下一個命令、||條件隔開,只有在上一個命令執行失敗後才執行下一個命令。
8.一、標準輸出重定向
(1) 使用>將輸出寫入文件,若是指定文件已存在將會刪除文件中原來的內容。如:ls /boot > boot.txt
(2) 使用>> 將輸出追加到文件,若是指定的文件已存在將會把輸出附加到文件中。
8.二、標準錯誤重定向
(1) 使用2> 將輸出寫入文件,若是指定的文件已經存在將會刪除文件中原來的內容。
(2) 使用2> 將輸出追加到文件
8.三、Shell腳本
腳本是爲了縮短傳統的「預處理-編譯-彙編-連接-運行」過程而建立的計算機編程語言。腳本一般是解釋運行而非編譯。Shell腳本是按行解釋的,每一個Shell腳本對系統來講就是一個文本文件,在有相應權限下能夠使用文本編輯器創建修改Shell腳本文件。
雖然在Linux中擴展名並無實際做用,可是爲了閱讀方便,腳本文件通常用sh做爲擴展名。
一行中「#」以後的內容表示是註釋,註釋在執行過程當中被忽略。
Shell腳本文件的第一行應該指定向哪一個解釋器發送指令,「#!/bin/sh」
在執行已編好的腳本時能夠使用兩種方式:對於有執行權限的腳本文件能夠使用「./<文件名>」的方式執行,對於沒有執行權限的腳本能夠使用「sh<文件名>」的方式執行。
Linux系統中每一個進程都是有壽命的,全部進程都是應另個進程的請求而啓動,發出請求的進程成爲父進程,新啓動的進程成爲子進程。子進程完成自身任務退出,子進程退出後會返回一個信息給父進程,叫作返回值或退出狀態,返回值是一個0~244之間的整數,進程返回0表示執行成功,任何非0都表示某種形式的失敗。shell 中把上一個命令的返回值保存在一個名爲「$?」的特殊變量中。能夠使用「echo $?」顯示上一個命令是否執行成功。
8.3.一、變量
變量就是會變化的量,Shell容許用戶設置和引用shell變量,shell 變量能夠用在命令和腳本中,也能夠被其餘程序做爲配置選項而引用。Shell變量有兩種類型:環境變量和局部變量。環境變量由子shell繼承,局部變量只存在於建立的shell中。每一個變量都有一個名稱,變量的名稱能夠是字母字符及下劃線組成不能以數字開頭。Shell在使用變量錢不須要專門的語句進行定義也不對變量區分數據類型,本質上全部的shell變量都是字符串,shell也運行比較和算術操做。
(1) 局部變量
局部變量的創建和賦值直接使用「變量名=變量值」的 方式。例如變量名strA,值爲ctu
strA=ctu
變量賦值能夠使用雙引號單不是必須的: strA=「ctu」
變量定義以後,用戶在不註銷的狀況下任什麼時候間均可以使用已定義的變量,在使用時必須在變量名前加一個$.例如顯示局部變量:echo $strA.
(2)、環境變量
Linux中容許全體進程使用「變量名=變量值」的方式定義被稱爲環境變量的變量。環境變量是保存在內核進程中的一部分,不管什麼時候開啓一個進程,子進程都會繼承環境變量。用戶也能夠建立環境變量,環境變量的建立分兩步,首先定義一個局部變量,而後使用「export」命令將局部變量提高爲環境變量。
set命令顯示已經定義的變量
env命令顯示已定義的環境變量
「unset<變量名>」清除變量 unset strA
8.四、向腳本傳遞參數
腳本中能夠使用「$1」接收傳遞給腳本的第一個參數,「$2」接收第二個參數,能夠使用「$*」接收全部的參數,使用「$0」得到當前腳本的名稱、使用「$#」獲取傳遞給腳本的參數個數,使用「$$」得到當前腳本的PID。
8.五、流程控制
程序語言通常都是從上向下執行代碼,shell經過判斷和循環改變腳本的順序執行。
(1)、判斷結構
if、then、else語句提供測試條件,語法以下:
if<條件>; then
#條件爲真時執行的內容
fi
if<條件>;then
#條件爲真時執行的內容。
else
#條件爲假時執行的內容。
fi
if<條件1>;then
#條件爲真時執行的條件
elif<條件2>;then
#條件2爲真時執行的內容。
else
#前兩個條件都爲假時執行的內容。
fi。
if語句都必須以fi終止,elif、else是可選的。
(2) case判斷結構
case 值 in
模式1)
# 符合模式1時執行的內容
;;
模式 2)
#符合模式2時執行的內容
; ;
esac
其中;;至關於C語言中的break。若是無匹配模式使用星號*匹配該值,再接收其餘輸入,至關於default。*表示任意字符,?表示任意單字符。
循環結構
bash shell 支持三總類型的循環:for循環一次處理循環體內容直到循環耗盡,until循環直到條件爲真前一次執行循環體內的內容,while循環直到條件爲假前一次執行循環體內的內容。
while[條件]
do
循環體
done
until [條件]
do
循環體
done
for((初始值;限制值;步長))
do
循環體
done。
有兩種方法退出或路過循環:(1)break 用於跳出循環,break直接跳出循環,執行循環後邊的,若是是循環嵌套使用break默認是跳出當前循環,也能夠指定跳出循環的個數break 2 跳出兩套循環。(2)continue 跳出本次循環,執行新一輪的循環。
8.六、函數
function 函數名
{
#函數內容
}
函數能夠放在同一個文件中做爲一段代碼,也能夠放在只包含函數的單獨文件中,使用函數時像執行腳本同樣傳入參數。在函數體內容也能夠用$1 $2的方式傳入參數。
9、Linux引導及進程管理
10.一、加載引導程序
BIOS自檢最後一步中BIOS把磁盤的第一個數據塊(MBR,Master Boot Record)裝入內存,並把執行傳遞這個區域,分爲兩個階段執行
(1) 第一階段,引導程序很小,惟一任務就是定位、裝載並把控制權傳遞給第二階段的引導程序,這段程序在MBR中因此在文件系統中找不到。
(2)第二階段,引導程序自己,可以讀取有關默認設備的配置信息。第二階段應道程序一般是文件系統中可識別的二進制文件,完成如下任務:編寫合適內核命令行,用於引用正確的根分區;裝載合適的初始虛擬磁盤;裝載合適的Linux內核並將控制權交給內核。
Ubuntu使用的引導程序是GRUB,GRUB是GNU項目的操做系統引導程序,在/boot/guab目錄下,主要配置文件是/boot/grub/grub.conf文件。
GRUB加載內核參數並把控制權交給內核後,Linux內核將完成如下操做:(1) 運行init進程,Linux內核啓動的第一個進程就是/sbin/init,這個命令是系統啓動時由內核執行的,所以其進程ID(PID)永遠是1,只要系統運行init進程就會一直運行,init進程也是系統中最後一個被終止的進程,該進程不接收SIGKILL 信號。init進程功能是啓動、中止、監控其餘進程。init啓動時會讀取配置文件/etc/inittab. inittab文件開機是執行,若是改變過了該文件須要重啓。用runlevel查看運行級別。
啓動時登陸shell首先讀取腳本文件/etc/profile,該腳本初始化各類環境變量如PATH、HOSTNAME。
10.二、Linux內核模塊
內核是操做系統的核心組成部分,主要兩個功能:一是充當資源管理器,向進程透明分配內存、CPU訪問等資源;二是充當解釋器,在進程和硬件之間專遞信息。
內核通常使用模塊和硬件設備交流,每一個模塊代碼都單獨放在一個目標文件中,能夠根據須要加載和刪除內核模塊,內核模塊位於/lib/modules/$(uname -r) 目錄中,用ls /lib/modules/$(uname -r)查看和管理模塊。
lsmod 命令顯示當前加載到內核的模塊。
modprobe 裝載內核模塊
rmmod 從內存中刪除內核模塊
10.三、/proc 目錄
proc文件系統是一個僞文件系統,只存在內存中,不佔用硬盤空間。
10.四、進程的狀態:可運行、自願休眠、非自願休眠、掛起的進程、殭屍進程。
free 查看內存狀態。
ps 查看進程。
pstree 以樹狀查看進程
top 顯示、管理執行中的程序。
11、網絡管理
Linux內核能夠檢測出全部連接的PCI設備,能夠使用lspci命令驗證計算機上的pci設備是否被內核檢測到。Linux內核不容許用戶以文件的形式訪問網卡,也就是在/dev目錄下無直接關聯網卡的設備節點。Linux經過網絡接口訪問網卡,並以相似eth0的方式命令,其中字母表示數據鏈接技術,eth(以太網)、ppp(ppp協議的串口設備)、fddi。
ifconfig命令能夠檢驗全部已識別的網絡接口命令。
ifconfig eth0 能夠只顯示網絡接口0的網絡信息。
ifconfig eth0 down 禁用以太網0接口
ifconfig eth0 up 啓用以太網0接口
11.一、靜態路由配置
IP協議以使用路由器鏈接在一塊兒的機器構成的網絡爲基礎,全部鏈接到單一IP網絡上的機器都有類似的IP地址,並一般使用相同的網絡交換機。
每一個Linux內核都會有個路由表,路由表歷來肯定對於一個發送出的數據包,內核使用哪一種方法傳遞數據包,路由表定義了哪一個網絡接口與本地網絡的關係,以及本地網絡上充當連接外邊網絡的機器的身份標識。「Flags」列有G的表示的是網關。
route 命令查看路由表
route -n 路由表按IP地址來顯示。
route add default gw IP ,增長新的網關
route del default gw IP ,刪除網關
11.二、ARP配置
ARP協議(地址解析協議),基本功能是經過目標的IP地址,查詢目標的MAC地址,ARP是IPv4網絡層中不可缺乏的,IPv6中再也不適用。
arp 查看arp
11.三、網絡測試
ping測試兩臺主機之間底層IP聯通性
ping IP 直接pingIP地址。
nsloopup 檢查DNS查詢結果
網絡抓包工具wireshark
12、DHCP
DHCP(動態主機配置協議),是一種網絡管理員可以集中管理和自動分配IP網絡地址的通訊協議。
十3、GCC編譯器和GDB調試器
GCC編譯器是GNU開源組織發佈的Linux下多平臺編譯器,將多種語言編寫的源程序編譯、連接成可執行文件,GDB是調試器。
13.一、連接庫
函數庫其實是一些頭文件(.h)或者庫文件(.so或者.a)的集合。Linux下大多數頭文件的默認路徑是/usr/include,庫文件默認路徑是/usr/lib/,有時候使用GCC編譯時須要爲其指定所須要的頭文件和庫文件的路徑。
GCC採用搜索目錄的方法查找所須要的文件,-I選項能夠向gcc頭文件搜索路徑中添加新的目錄,假如在當前目錄下編寫了foo.c,而在/home/yang/include/目錄下有編譯改程序時所須要的頭文件(不是在/usr/include/目錄下),爲了使GCC可以順利找到,能夠使用I選項:
gcc foo.c -I /home/yang/include -o foo
若是使用了不在標準庫位置的庫文件,能夠使用-L選項向gcc庫文件搜索路徑中添加新的目錄,假如在/home/yang/lib/目錄有foo.c所須要的庫文件。
gcc foo.c -L /home/yang/lib -lfoo -o foo
編譯命令中,-l選項,指示gcc去連接庫文件libfoo.so,庫文件命名時有一個約定,以lib三個字母開頭,所以在用-l選項指定連接庫文件名時省去了lib三個字母,也就是說gcc對-lfool進行處理時,會自動搜索libfoo.so文件。
Linux下庫文件分爲兩大類:動態連接庫(以.so結尾)和靜態連接庫(一般以.a結尾),區別是所需的代碼是在運行時動態加載的仍是編譯時靜態加載的。默認狀況下gcc連接時優先使用動態連接庫,只有在動態鏈接口不存在時才考慮使用靜態連接庫。若是連接庫裏同時有libfoo.so libfoo.a兩個庫文件,爲了使用靜態庫文件,使用以下命令:
gcc foo.c -L /home/yang/lib -static -lfoo -o foo
13.二、同時編譯多個源程序
若是一個程序有多個源文件組成,foo1.c foo2.c foo3.c 對他們編譯生成foo可執行程序,命令以下:
gcc foo1.c foo2.c foo3.c -o foo 等價於下列命令:
gcc -c foo1.c -o foo1.o
gcc -c foo2.c -o foo2.o
gcc -c foo3.c -o foo3.o
gcc foo1.o foo2.o foo3.o -o foo
13.三、管道
GCC生成可執行文件時,須要通過預處理、編譯、彙編、連接,幾個步驟,並且每一個步驟都須要一個臨時文件來保存信息,當源文件不少時將會增長系統的開銷,能夠使用管道來減少開銷,
gcc -pipe foo.c -o foo
十4、make的使用和makefile的編寫
make工程管理器是Linux下的一個「自動編譯管理器」,「自動」是指它可以根據文件的時間戳,自動發現更新過的文件而減小程序編譯的工做量,它經過讀入Makefile文件的內容來執行大量的編譯工做。
make機制的運行環境須要一個命令行程序make和一個文本文件Makefile。make是一個命令工具,用來解釋makefile的命令。
假如一個程序 由main.c foo1.c foo2.c foo3.c 組成,makefile文件內容:
all: main.c foo1.c foo2.c foo3.c
gcc main.c foo1.c foo2.c foo3.c -o all
這5個文件應當存放在Linux的同一個目錄下,使用make進行自動編譯的時候,它會在這個目錄下找到makefile文件,在存放文件的目錄下輸入make命令進行編譯。
make是一個Linux下的二進制文件,自動尋找名稱爲Makefile的文件做爲編譯文件,若是沒有則尋找makefile文件做爲編譯文件。
make操做管理Makefile文件的規則:
(1) 若是這個工程沒有編譯過,那麼全部C文件都須要被編譯和連接。
(2) 若是這個工程的某幾個C文件被修改,則只需編譯被修改過的C文件,並鏈接目標程序。
(3) 若是這個工程的頭文件被修改了,則須要編譯引用這個頭文件的C文件,並鏈接至目標程序。
反斜槓「\」爲換行符,某一條規則或命令不能在一行中寫完時,能夠用它表示換行。5.2程序能夠保存爲當前目錄下的Makefile文件或makefile文件,或makefile文件夾下的文件,在該目錄下直接輸入命令make就能夠自動生成可執行文件all,若是要刪除可執行文件和全部的中間目標文件,執行make clean 命令就能夠了。
在Makefile中,目標名稱指定有如下慣例(固然能夠不適用這些慣例):
all:表示編譯全部內容,是執行make時默認的最終目標。
clean:表示清除全部的目標文件。
disclean:表示清除全部內容。
install:表示進行安裝的內容。
5.2所示Makefile中,目標包含以下內容:最終可執行文件all和8箇中間文件*.o;依賴文件即每一個冒號後邊的那些.c和.h文件,每一個.o文件都有一組依賴文件,這些.o文件又是最終all的依賴文件,依賴關係及說明目標文件是由哪些文件生成。定義好依賴關係,後續的代碼定義了生成目標的方法,注意必定要以一個Tab鍵作爲開頭。
14.一、makefile的書寫規則
makefile書寫包含兩個:一個是依賴關係,一個是生成目標的方法。
makefile中的命令必須以tab鍵開頭。
Makefile中的變量就像是c C++中的宏,表明了一個字符文本,在Makefile執行的時候就會展開,變量能夠使用在目標、依賴目標,命令或是makefile的其餘部分中。
變量的命名能夠包含字符、數字、下劃線(能夠是數字開頭),可是不能有 ‘:’’ #‘ ‘ =‘或是空格、回車,變量名區分大小寫。變量在聲明時須要給予賦初值,使用時須要在變量前邊加上「$」符號,最好用小括號「()」或花括號"{}"把變量給括起來。若是要使用真實的「$」字符,那麼須要用"$$"
除了使用「=」給變量賦值外,Makefile還支持嵌套定義,例如
執行make all 將會輸出 Huh?,Makefile變量的這個特性有利有弊,好處是能夠把變量真實值推到後面來定義如:
CFLAGS=$(include_dirs) -O
include_dirs=-Ifoo -Ibar
當CFLAGS在命令中被展開時,會是 -Ifoo -Ibar -O ,使用這種形式的弊端就是遞歸定義可能會出問題如:
A=$(B)
B=$(A)
這會讓make陷入無限循環的變量展開過程當中去,make有能檢測這樣的定義,並報錯,爲了不無限循環,定義了另一種變量「:=」如:
x :=foo
y :=$(x) bar
x :=later
等價於
y := foo bar
x := later
":="操做符,使得前邊的變量不能使用後面的變量,只能使用前面已經定義好了的變量,若是是這樣:
y:=$(x) bar
x :=a
那麼y的值是bar 而不是 a bar
「?=」操做符:foo?=bar,若是變量foo沒有被定義過,那麼變量foo的值就是bar,若是foo被定義過,那麼這條語句什麼都不作。等價於
ifeq($(origin foo),undefined)
foo=bar
endif
另一種操做符「+=」給變量追加值,如:
objects= main.o foo.o
objects +=another.o
等價於
objects= main.o foo.o
objects := $(objects) another.o
define 關鍵字:使用define關鍵字設置變量的值能夠有換行,define指示符後面是變量的名字,另起一行定義變量的值,定義是以endef關鍵字結束,define中的命令也都是以Tab鍵開頭,不然make將不把它當作命令。
define two-line
echo foo
echo $(bar)
endef
十5、文件的IO操做
有關I/O操做分爲兩類:基於文件描述符的IO操做,基於流的IO操做。
Linux中,文件提供了簡單並一致的接口來處理系統服務與設備,全部的內容都被當作文件,全部的操做均可以歸結爲對文件的操做。操做系統能夠像處理普通文件同樣來使用磁盤文件,串口,鍵盤,顯示器,打印機及其餘設備。
普通文件:文本文件、二進制文件。普通文件能夠直接查看,二級制文件不能打開。
目錄文件:只有root用戶能寫目錄文件,其餘用戶只能讀。
設備文件:爲操做系統和IO設備提供連接的一種文件,Linux把設備的IO做爲普通文件讀取和寫入,操做內核提供對設備處理和對文件處理統一的接口,每一個IO設備都對應一個設備文件,存放在/dev目錄 中。
連接文件:提供了一種共享文件的方法。
管道文件:用於進程間傳遞數據,是進程間通訊的一種機制。
套接口文件:在不一樣計算機的進程間通訊也叫套接字。套接字是操做系統內核中的一個數據結構,是網絡中節點進行通訊的關鍵。套接字有三種類型:流式套接字,數據報套接字,原始套接字。流式套接字也就是TCP套接字(面向鏈接的套接字),數據報套接字也就是UDP套接字(無鏈接的套接字),原始套接字用「SOCK_RAW」表示。
15.一、文件描述符
Linux用文件描述符來訪問文件,文件描述符是一個非負整數,用於描述被打開的文件索引值。當內核打開或新建一個文件時,就會返回一個文件描述符。文件描述符0與標準輸入相結合,文件描述符1與標準輸出相結合,文件描述符2與標準出錯相結合。POSIX中用STDIN_FILENO STDOUT_FILENO STDERR_FILENO來代替0、一、2.這三個符號常量位於頭文件unistd.h
15.二、文件重定向
shell提供一種方法,任何一個或這三個描述符都能重定向都某一個文件,而不是默認的輸入或輸出設備。如:
ls>file.list
15.三、文件的建立、打開與關閉
對一個文件操做,首先要求這個文件存在,其次在操做以前將這個文件打開,這樣才能對文件進行操做,操做完成後,必須將文件關閉。
(1) open 函數能夠打開或建立一個文件,函數說明以下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname ,int flags) ; //打開一個如今文件
int open(const char *pathname ,int flags,mode_t mode); // 打開的文件不存在,則先建立它
返回:若成功,返回文件描述符,若出錯返回-1.
參數pathname是一個字符串指針,它指向須要打開(或建立)文件的絕對路徑或相對路徑名。
參數flags用於描述打開文件的方式,以下表所示,定義在fcntl.h頭文件中,flags的值能夠由表中取值邏輯或獲得。O_RDONLY,O_WRONLY,O_RDWR這三個參數只能出現一個。
參數mode用於指定所建立文件的權限,使用按位邏輯或的方法進行組合。
建立文件creat()函數,函數原型以下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname,mode_t mode);
返回:若成功,返回以只寫方式打開的文件描述符,若出錯返回-1. 參數pathname和mode與open函數的意義相同。
create等效於:open(pathname,O_WRNOLY|O_CREAT|O_TRUNC,mode);
creat的不足之處是以只寫的方式打開所建立的文件,若是要建立一個臨時文件,並要先寫該文件而後讀該文件,則必須先調用create、close,而後再調用open 。
(3)close函數
close函數用於關閉一個文件,函數說明以下:
#include <unistd.h>
int close(int fd);
返回:若成功返回0,出錯返回-1.參數fd是需關閉文件的文件描述符。
(4) 文件的定位
每一個打開的文件都有一個與其相關聯的「當前文件位移量」,它是一個非負整數,用以度量從文件開始處計算的字節數。打開一個文件時,除非指定O_APPEND選擇項,不然該位移量被設置爲0.能夠調用lseek函數顯示的定位一個打開文件,函數說明以下:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence); 返回:若成功,返回新的文件位移量,若出錯爲-1.「lseek」l表示長整型。
fd:文件描述符,offset 表示位移量大小單位字節,
(5) read函數
讀寫是文件操做的核心內容,實現文件的IO操做必須進其進行讀寫。read函數說明以下:
#include <unistd.h>
ssize_t read(int fd ,void *buff,size_t count);
返回:讀到的字節數,若已讀到文件尾返回0,若出錯返回-1.
fd,文件描述符,buff存放讀取的字節,count要讀取數據的字節數。
讀操做從當前位移量處開始,在成功返回以前,該位移量增長實際讀獲得的字節數。多種狀況實際讀到的比要讀的少:
讀普通文件時,在讀到要求的個數字節以前讀到了文件末尾,好比讀到文件末尾讀了30個字節,要求讀100個字節,則read返回30,下一次再調用read時返回0.
從終端設備讀時,一次最多讀一行。
當從網絡讀時,網絡中的緩衝機構可能形成返回值小於要求讀的字節數。
某些面向記錄的設備,例如磁帶,一次返回一個記錄。
(6) write函數
用write函數向打開的文件寫數據,函數說明以下:
#include <unistd.h>
ssize_t write(int fd,void *buf,size_t count);
返回:一般與count值相同,不然出錯。
對於普通文件,寫操做從文件的當前位移量開始。若是打開文件時指定了O_APPEND選擇項,則在每次寫操做以前,將文件的位移量設置在文件的結尾處。
od -c 文件名路徑,查看該文件的實際內容,命令行中的-c表示以字符的方式打印文件內容。
15.四、文件的屬性
Linux的文件系統具備比較複雜的屬性,包括文件訪問權限、文件全部者,文件自己,文件長度等。
(1) 改變文件的訪問權限
chmod、fchmod 這兩個函數能夠改變現存文件的權限。
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *pathname,mode_t mode);
int fchmod(int fd,mode_t mode);
chmod函數在指定文件上進行操做,pathname是絕對路徑或相對路徑;fchmod對已經打開的文件進行操做,fd是文件描述符, mode是權限。
shell中直接用chmod命令改變文件權限 好比 chmod 755 文件絕對路徑或相對路徑。
(2) 改變文件全部者
用戶能夠調用chown 、fchown 、和lchown 來改變一個文件全部者識別號和組識別號。
#include<sys/types.h>
#include <sys/stat.h>
int chown(const char *pathname,uid_t owner,gid_t group);
int fchown(int fd,uid_t owner,gid_t group);
int lchown(const char *pathname,uid_t owner,gid_t group);
三個函數若成功返回0,失敗返回-1. pathname 絕對路徑或相對路徑,owner 新的擁有者, group 新的組。
chown 修改指定文件的全部者和組。
fchown 修改已經打開的文件的全部者和組。
lchown 針對符號連接文件。
(3) 重命名
一個普通文件或者一個目錄文件均可以被重命名,rename函數以下:
#include <stdio.h>
int rename(const char *oldname,const char *newname);
返回:若成功返回0,若出錯返回-1. rename參數會將oldname所指定文件名稱改成參數newname所指定的文件名稱,若newname存在則會刪除。oldname和newname指向同一個文件時不會作任何修改。
不能將一個目錄文件重命名爲它的子文件。
(4) 修改文件的長度
stat結構體成員st_size 包含了一字節爲單位的文件的長度,此字段只對普通文件、目錄文件和符號連接文件有意義。
對於普通文件,其文件長度能夠是0.
對於目錄文件,文件長度一般是一個數,例如16或512的整數倍。
對於連接文件,文件長度是在文件名中的實際字節數。
截短文件能夠調用函數truncate 和ftruncate,說明以下:
#include <sys/types.h>
#include <unistd.h>
int truncate(const char *pathname,off_t len);
int ftruncate(int fd ,off_t len);
返回:若成功返回0,若出錯返回-1.
15.五、 文件的其餘操做
(1) stat、fstat、lstat函數
Linux系統中全部的文件都有一個對應的索引節點,該節點包含了文件的相關信息,這些信息保存子啊stat結構體中,可經過這三個函數進行查看。
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *pathname,struct stat *sbuf);
int stat(int fd,struct stat *sbuf);
int lstat(const char *pathname, struct stat *sbuf);
返回:成功返回0,出錯返回-1.
頭文件<sys/types.h>中定義了某系和實現有關的數據類型,被稱爲基本系統數據類型,頭文件中的這些數據類型都是用typedef 定義的,絕大多數都以 _t 結尾。
(2) dup dup2函數
這兩個函數用來服裝一個現存的文件描述符。
#include <unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);
(3) fcntl函數,能夠改變已經打開的文件的性質。
15.五、特殊文件的操做
(1) 建立目錄 mkdir
(2) 刪除空目錄 rmdir
(3)opendir closedir readdir
十6、基於流的IO操做
流IO是C語音的標準庫提供的,這些IO能夠代替系統中提供的read和write函數。
流和FILE對象:上一章對IO操做是基於文件描述符的,打開文件返回文件描述符,而後基於文件描述符對文件進行操做。對於標準的IO庫,操做則是基於流進行。用標準的IO打開或建立一個文件是,已經使一個流和一個文件相結合。
打開一個流時,標準IO函數fopen返回一個指向FILE的指針。對流的IO操做相似對文件描述符的IO操做,調用fopen函數打開一個文件,並返回一個FILE指針,流成功打開後,就能夠調用標準IO進行操做 。當完成操做後,須要執行清空緩衝、保存數據等操做。而後將流關閉,若是不關閉流,可能形成數據的丟失,fclose().
16.一、標準輸入、標準輸出、標準出錯
使用流IO時,會自動打開標準輸入、標準輸出、標準出錯。文件描述符用STDIN_FILENO STDOUT_FILENO STDERR_FILENO 來表示,這三個符號常量在<unistd.h>中。
基於流IO是,經過預約義文件指針,stdin stdout stderr來引用標準輸入、標準輸出、標準出錯的,定義在頭文件<stdio.h>中。
16.二、 緩存
基於流的操做最終會調用read和write函數進行IO操做。爲了儘量減小使用read和write函數的次數,流對象一般會提供緩衝區(緩存),標準IO提供了3中類型的緩存:
全緩存:直到緩衝區被填滿,才調用系統IO函數。
行緩存:直到遇到換行符「\n」才進行IO操做。
無緩存:數據會當即讀入或輸出到外存文件或設備上。
16.三、設置緩存的屬性
緩存具備本身的屬性,包括緩衝區的類型和緩衝區的大小。調用fopen打開一個流時,就開闢了緩衝區,系統會賦予其一個默認的屬性值。也能夠根據本身需求來設定緩衝區的屬性值,調用以下函數:
#include <stdio.h>
void setbuf(FILE *fp,char *buf);
void setbuffer(FILE *fp,char *buf,size_t size);
void setlinebuf(FILE *fp);
int setvbuf(FILE *fp,char *buf,int mode,size_t size); 返回:0 成功,非0 失敗
這四個函數對流屬性進行操做,操做對象是一個已經打開的流。
fp 指向FILE結構體的指針。
setbuf 用於將緩衝區設置爲全緩存或無緩存,參數buf執行緩衝區的指針。buf指向一個真實緩衝區地址時,此函數將緩衝區設置爲全緩衝,大小由預約義常數BUFSIZ指定,當buf爲NULL時,設置爲無緩衝,此函數,當作激活或禁止緩衝區的開關。
setbuffer的功能和使用方法與setbuf相似,區別是有程序員指定緩衝區的大小,由size肯定。
setlinebuf 用於將緩衝區設定爲行緩存。
setvbuf 比較靈活,fp buf size含義與setbuffer函數相同,mode用於指定緩衝區類型,_IOFBF全緩存、_IOLBF 行緩存、_IONBF 無緩存。三個常量在<stdio.h>中,設定爲_IONBF時參數buf和size是沒用的。
最好在打開流還沒對流操做以前,設置流的屬性。
16.四、緩存的沖洗
沖洗,就是將IO操做寫入緩存中的內容清空,清空能夠是將緩存區內容丟掉也能夠是保存到文件中,相應庫函數以下:
#include<stido.h>
int fflush(FILE * fp);
#include<stdio_ext.h>
void fpurge(FILE *fp);
fflush函數將緩存區還沒有吸入文件的數據強制性寫入文件中,成功返回0,失敗返回EOF。
fpurge函數,用於將緩衝區中的數據徹底清除。
16.五、流的打開與關閉
對一個流操做以前,先將他打開,也就是創建某一個流同某個文件或設備的關聯,只有這樣才能對這個流進行操做。打開流函數以下:
#include <stdio.h>
FILE *fopen(const char *pathname,const char *type);
FILE *freopen(const char *pahtname,const char *type,FILE *fp);
FILE *fdopen(int fd,const char *type);
三個函數若成功返回文件指針,若出錯則爲NULL。
三個函數的區別有如下幾點:
fopen 打開一個文件由pathname指定文件。
freopen 在一個特定流(有fp指示)打開一個指定的文件(路徑名有pathname指示),若該流已經打開則先關閉。此函數用於將一個指定的文件打開爲一個預約義的流:標準輸入、標準輸出,或標準出錯。
fdopen 取一個現存的文件描述符,並使一個標準的IO流與該描述符相結合。此函數經常使用於由建立管道和網絡通訊通道函數得到的描述符,由於這些特殊類型文件不能使用標準的IOfopen函數。
type參數,指定了該IO流的讀寫方式,該值以一個字符串的形式傳入。
type 取值字符串中包含 a的表示 追加寫,即流打開之後,文件的讀寫位置在文件的末尾。type 字符串中包括字母b的表示流以二進制的形式打開,其餘的則表示以文本的形式打開。對於Linux系統來講沒有意義,由於Linux系統下,二進制文件和文本文件都是普通文件,是字節流。
fopen打開成功返回文件指針,若出錯則返回NULL,出錯緣由有如下三種:
指定路徑有錯誤
type參數是一個非法的字符串
文件的操做權限不夠。
fdopen函數用在一個已經打開的文件描述符上打開一個流。與fopen不一樣,因爲文件已經打開,fdopen不會建立文件,也不會將文件截短爲0.
(2) 流的關閉
在所需的操做完成之後,必須將流關閉。fclose用於關閉一個流,函數以下:
#include <stdio.h>
int fclose(FILE *fp);
若成功則返回0,若失敗則返回EOF(-1,定義在stdio.h)。
對流的操做完成後,必須關閉它,大多數流的操做都是基於緩衝機制的,fclose在關閉流以前會將緩衝區的內容寫入文件或者設備。fclose若是關閉的是本地文件,出錯的概率很小,若是關閉的是一個網絡環境中的遠程文件,fclose函數就有可能出錯,這時就要檢查返回值了。
15.六、流的讀寫
打開了流,則可在4種不一樣類型的IO進行選擇,對其進行讀、寫操做。
基於字符的IO:每次讀寫一個字符數據的IO方式,若是流是帶緩存的,則由標準IO函數處理全部緩存。
基於行的IO:當輸入內容遇到‘\n’換行符的時候,則將換行符以前的內容送到緩衝區IO中的方式成爲基於行的IO。
直接IO:輸入輸出操做以記錄爲單位進行讀寫。
格式化IO:printf scanf 函數。
(1) 基於字符的IO
基於字符的IO一般是處理單個字符的。如下3個函數用於讀入一個字符:
# include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
返回:若成功則返回讀入字符的值,若已處文件尾端或出錯則爲EOF。
前兩個函數中,參數fp表示要讀入字符的文件,getc可被實現爲宏,fgetc不能實現爲宏。getc的參數不能是具備反作用的表達式。(反作用表達式:經過++ 等操做改變參數的值)
getchar只能用來從標準輸入輸出流總輸入數據,至關於調用以stdin爲參數的getc函數即,getc(stdin) 。
這三個函數以unsigned char 類型轉換爲int的方式返回下一個字符。
(2) 字符的輸出
如下三個函數用於字符的輸出:
#include <stdio.h>
int putc(int c FILE *fp);
int fputc(int c ,FILE *fp);
int putchar(int c);
返回: 若成功則爲C,若出錯則爲EOF。
putc和fputc第一個字符表示要輸出的字符,第二個參數表示輸出的文件,若是成功輸出一個字符,則返回輸出的字符,若出錯則返回EOF。
與輸入函數同樣,putchar(c)等同於putc(c,stdout);putc可被實現爲宏,fputc不能實現爲宏。
(3) 基於行的IO
當輸入內容遇到‘\n’換行符的時候,則將流中\n以前的內容送到緩衝區的IO方式成爲基於行的IO。
行的輸入:
fgets和gets函數實現輸入一行字符串,函數以下:
#include <stdio.h>
char *fgets(char *buf,int n,FILE *fp);
char *gets(char *buf);
返回:若成功返回緩衝區首地址,若已處文件尾或者出錯則爲NULL。
fgets函數的第一個參數表示存放讀入串的緩衝區,第二個參數n表示讀入字符個數,不能超過緩存區長度。fgets函數一直讀知道遇到一個換行符爲止,若是在n-1個字符內未遇到換行符,最後一個字節用於存放字符串結束標誌\0 ,fgets函數會將換行符存入緩衝區。
gets函數從標準輸入讀取一行並將其存入一個緩衝區。
行的輸出:
fputs和puts 函數實現輸出一行字符串,函數原型以下:
#include <stdio.h>
int fputs(const char *buf,FILE *restrict fp);
int puts(const char *str);
fputs第一個參數表示存放輸出內容的緩衝區,第二參數表示要輸出的文件。成功返回輸出的字節數,失敗返回-1.
puts 用於向標準輸出輸出一行字符串。
(3)直接IO
字符讀寫和行的讀寫函數是以一個字節或一次一行的方式進行IO操做,好比一次讀或寫整個機構,爲了使用getc或putc,必須循環整個機構,一次讀或寫一個字節,fputs遇到null或換行符字節就中止, 二進制IO操做解決了這個問題:
#include <stdio.h>
size_t fread(void *ptr,size_t size,size_t nmenb,FILE *fp);
size_t fwrite(void *ptr,size_t,size_t nmenb,FILE*fp);
ptr 緩衝區指針,size 目標文件的大小,nmemb 欲讀取或寫入的字節個數,fp文件指針。
格式化的IO:
格式化IO是IO最多見的IO方式,好比printf 和scanf
格式化輸出有4個printf函數:
#include <stdio.h>
int printf(const char *format,...);
int fprintf(FILE *fp,const char *format,...);
兩個函數的返回,若成功返回實際輸出的字節數,若出錯爲負值。
int sprintf(char *st,const char *fromat,...);
int snprintf(char *st,size_t size,const char *format,...);
格式化輸入的3個scanf函數:
#include <stdio.h>
int scanf(const char *format,...);
int fscanf(FILE *fp,const char *format,...);
int sscanf(char *str,const char *format,...);
十6、進程控制
進程是一個程序的一次執行過程,程序是進程的一種靜態描述,系統中運行的每一個程序都是在它的進程中運行的。進程:在自身虛擬空間運行的一個單獨的程序。進程的要素:有一段程序供進程運行,專用的系統堆棧空間,進程控制塊(task_struct),獨立的存儲空間。進程缺乏一個要素時,咱們成其爲線程。
Linux系統中全部的進程都是由一個進程號爲1的init進程衍生而來的。Linux有3中進程:交互進程(shell)、批處理進程,監控進程(守護進程)。
每一個進程在建立時都會被分配一個數據結構,成爲進程控制塊(process control block ,PCB)。PCB包括一些信息:進程標識符,進程當前狀態,進程相應的程序和數據地址,進程資源清單,進程優先級,CPU現場保護區,進程同步與通訊機制,進程所在隊列PCB的連接字,與進程相關的其餘信息。進程ID(PID)是一個非負整數範圍 0--32767,Linux的專用進程:ID 0 是調度進程,經常成爲交換進程。ID1 是init進程,UNIX早期版本中是/etc/init 新版本是/sbin/int。該進程負責在內核自舉後啓動一個Unix系統。inti一般讀與系統有關的初始化文件/etc/rc*,並將系統引導到一個狀態,init進程不會終止。一個或多個進程合起來構成進程組,一個或多個進程組合起來構成一個會話。這樣能夠對進程進行批量操做。
ps 查看本身系統中目前有多少個進程,ps -aux 列出系統中進程的詳細信息。
Linux 提供getpid函數來返回系統當前前程的PID,函數以下:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
16.一、進程的控制是經過函數調用實現的,其中包括系統調用函數也包括庫函數。接下來學習進程的建立、等待、終止等具體操做的相關函數調用。
(1) fork 和vfork 函數
建立一個進程,最基本的系統調用是fork,系統用fork派生一個進程,函數以下:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回: 若成功,父進程中返回子進程ID,子進程中返回0,若出錯返回-1.
fork的做用是複製一個進程。子進程是父進程的複製,即子進程從父進程獲得了數據段和堆棧的複製,這些須要分配新的內存,而只讀的代碼段,一般使用共享內存的方式訪問。
fork函數的用途:一個進程但願複製自身,從而父子進程能執行不一樣段的代碼,進程想執行另一個程序。建立新進城後會返回給父進程子進程的ID,由於沒有一個函數獲得一個父進程全部子進程的ID,子進程返回0,由於子進程能夠經過調用getppid()函數獲得父進程的 pid。在fork以後是進入父進程仍是子進程不肯定。
Linux中建立新進程的方法只有一個,就是fork ,system()最後調用的也是fork。
另外一個建立進程的方法vfork,函數以下:
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
返回和fork同樣:父進程中返回子進程的ID,子進程返回0,返回-1錯誤。
fork和vfork區別:fork要複製父進程的數據段,vfork不須要徹底複製父進程的數據段,在子進程沒有調用exec或exit以前,共享數據段。fork不對父子進程的執行順序進行任何限制,在vfork調用中,子進程先運行父進程掛起,子進程調用exec或exit以後父進程的執行次序纔再也不有限制。
(2) exec() 函數
Linux使用exec函數來執行新的程序,以新的子進程徹底代替原有的進程,exec是一個函數族,指的是一組函數,一共有6個:
#include <unistd.h>
int execl(const char *pathnaem,const char *arg,...);
int execlp(const char *filename,const char *arg,...);
int execle(const char *pathname,const char *arg,...,char *const envp[]);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *filename,char *const argv[]);
int execve(const char *pathname,char *const argv[],char *const envp[]);
返回:若成功無返回值,若出錯 -1
函數命中含有字母「l」的,其參數個數不定,參數由所調用程序的命令行參數列表組成,最後一個NULL表示結束。
函數名中含有字母「v」的,則是使用一個字符串數組指針argv指向參數列表,這一字符串數組和含有字母「l」的函數中的參數徹底相同,一樣以「NULL」結束。
函數名中含有字母「p」的函數能夠自動在環境變量PATH指定的路徑中搜索要執行的程序,所以它的第一個參數爲filename,表示可執行函數的文件名。而其餘函數須要用戶在參數列表中指定該程序路徑,因此其第一個參數爲pathname。
函數名中有字母「e」的,比其餘函數多含有一個參數envp,這是一個字符串數組指針,用於指定環境變量。調用函數execle,execve 時,用戶自行設定子程序的環境變量,存放在參數envp所指定的字符串數組中,這個字符串數組也必須由NULL結束。其餘函數則是接收當前環境變量。
execve纔是真正意義上的系統調用,其餘都是在此基礎上通過包裝的庫函數。exec函數族做用是根據指定的文件名找到可執行文件,並用它來取代調用進程的內容,也就是在調用進程內部執行一個可執行文件。這裏的可執行文件既能夠是二進制文件,也但是任何Linux下可執行的腳本文件。
exec函數族的函數執行成功後不會返回,由於調用進程的實體,包括代碼段,數據段和堆棧等都已經被新的內容取代,只是進程ID等一些表面上的信息保持原樣。若是調用失敗了,纔會返回-1,從原程序的調用點接着往下執行。
當有程序認爲不能作貢獻了,它能夠調用任何一個exec,讓本身以新的面貌重生。廣泛狀況是,若是進程想執行另外一個程序,它就能夠fork一個新進程,而後調用任何一個exec,這樣看起來好像經過執行應用程序而產生了一個新進程同樣。
fork調用進程的數據段和堆棧會複製到新的子進程,而fork以後咱們調用exec函數會將複製過來的東西會被抹掉,很浪費時間,因而設計了一種copy on write技術,fork結束後並不當即複製父進程內容,到了真正實用的時候才複製。
理解exec:
實際的main函數 int main(int argc,char *argv[],char *envp[]);
參數argc指出了運行該程序時命令行參數的個數,數組argv存放了全部命令行參數,數組envp存放了全部的環境變量。環境變量指的是一組值,從用戶登陸後就一直存在,不少應用程序須要依靠它來肯定系統的一些細節,最多見的環境變量是PATH,它指出了應到哪裏去搜索應用程序,如/bin HOME也是比較常見的環境變量,她指出了咱們在系統中的 我的目錄。環境變量通常以字符串「XXX=xxx」的形式存在,XXX表示變量名,xxx表示變量值。
argv數組和argvp數組存放的都是指向字符串的指針,這兩個數組都以一個NULL元素表示數組的結尾。
(3) exit()和_exit() 函數
系統調用是用來終止一個進程的,執行到exit系統調用,進程就會中止剩下的全部操做,清除包括PCB在內的各類數據結構,並終止本進程的運行,函數原型:
#include <stdlib.h>
_exit()函數用於正常終止一個程序,函數原型:
#include <stdlib.h>
void _exit(int status);
status取值:0 表示沒有意外的正常結束;其餘數值表示出現了錯誤,進程非正常結束,實際編程時能夠用wait系統調用接收子進程的返回值。
區別:_exit()當即進入內核,exit先執行一些清除處理(包括調用執行終止處理程序,關閉標準的IO等)而後進入內核。
一個進程調用了exit後,該進程並不立刻消失,而是留下一個成爲殭屍進程的數據結構,不佔用內存。
(3) wait 和waitpid 函數
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid,int *status,int options);
若成功返回進程ID,失敗返回-1。
進程一旦調用了wait,就當即阻塞本身,有wait自動分析是否當前進程的某個子進程已經退出,若是讓它找到一個殭屍子進程,wait就會收集這個子進程的信息,並把它完全銷燬後返回;若是沒有找到這樣一個子進程,wait就會一直阻塞在這裏,只有有一個出現爲止。
參數status用來保存被收集進程退出時的一些狀態,它是一個指向int類型的指針。若是對這個子進程是若是死掉的絕不關心,則能夠設定這個參數爲NULL。
pid=wait(NULL);
若是成功,wait會返回被收集的子進程ID,若是調用進程沒有子進程,調用就會失敗,返回-1,errno被置位ECHILD。
wait和waitpid做用相同,waitpid用來指定等待的進程,能夠使進程不掛起而當即返回。參數pid指定所等待進程,
options提供了一些額外的選項來控制waitpid,Linux支持WNOHANG WUNTRACED,能夠使用|將這兩個參數連接起來,也能夠設置爲0.
進程簡述:fork執行產生了一個和父進程同樣的進程(數據段、堆棧,共享代碼段),隨着exec執行,新進程金蟬脫殼,開始一個全新的進程,並替代原來的進程。進程結束能夠天然結束或被其餘進程結束:本身結束執行到main}或者調用exit函數(留下殭屍進程)、return函數,wait、_wait函數清除掉殭屍進程。
(5) 用戶ID和組ID。
與某一進程相關聯的ID有6個:實際用戶ID、實際組ID、有效用戶ID、有效組ID、保存的設置用戶ID、保存的設置組ID,一般,有效用戶ID等於實際用戶ID,有效組ID等於實際組ID。相關函數:
#include <sys/types.h>
#include <unistd.h>
uid_t getuid(void);
gid_t getgid(void);
gid_t getegid(void);
uid_t gettuid(void);
返回:進程的相關用戶ID。
getuid用於得到實際用戶標識符,getgid得到實際的組ID,gettuid得到有效的組ID,getegid得到有效的組標識符。
(6) system 函數
system函數是一個和操做系統先關的函數,用戶能夠使用它在本身的程序中調用系統提供的各類命令。system函數原型:
#include <stdlib.h>
int system(const char *cmdstring);
十7、信號
信號是進程間通訊的機制,信號不是將數據發送給某一進程,而是用於通知一個進程某一個特定事件的發生。信號全稱爲軟中斷信號,也叫軟中斷。軟中斷信號用來通知進程發生了異步事件,進程之間能夠互相經過系統調用kill()發送軟中斷信號,內核也能夠給進程發送信號。信號用來通知某個進程發生了某個事件,並不給進程傳送數據。
進程處理信號的方法:(1)相似於中斷的處理程序,對於須要處理的信號,進程能夠指定處理函數。(2)忽略某個信號,對信號不作任何處理。(3) 對該信號的處理保留系統的默認值,大多數是使得進程終止,進程經過系統調用signal()來指定進程對某個信號的處理。
進程表的表項中有一個軟中斷信號域,該域中的每個位對應一個信號,當有信號發給進程時對應位置位。進程對不一樣的信號能夠同時保留,對於同一個信號,進程並不知道來過多少個。
每一個信號都有一個名字,都以SIG開頭。例如SIGABRT是夭折信號,進程調用abort()函數時產生這種信號。SIGALRM是鬧鐘信號,alarm()函數設置的時間超事後產生此信號。頭文件<signal.h>中,這些信號都被定義爲正整數,成爲信號編號,編號爲0的成爲空信號。
shell下鍵入kill -l 或者man 7 signal 查看信號。
17.一、內核對信號的處理
內核給進程發送軟中斷的方法:在進程所在的進程表中的信號域設置對應的位(內核經過在進程struct task_struct結構中信號域中設置相應的位來實現向進程發送一個信號)。進程檢查是否收到信號的時機:進程即將從內核態返回用戶態時,因此進程處於內核態時軟中斷信號不當即起做用,進程要返回用戶態時先處理完信號才返回用戶態,或者一個進程要進入或者離開一個適當的低優先級睡眠狀態時。
17.二、信號操做的相關函數
(1) signal函數
要對一個信號進行處理,須要給出此信號發生時系統所調用的處理,能夠做爲一個特定的信號註冊相應的處理函數。若是源程序註冊了針對某一個特定信號的處理程序,不論當時程序執行到何處,一旦進程接收到該信號,相應的調用就會發生,調用signal函數來註冊某個特定信號的處理程序,函數以下:
#include <signal.h>
void (*signal(int signum,void (*handler)(int)))(int);
返回:若成功則返回之前的信號處理配置,若出錯則爲SIG_ERR
參數signum,所註冊函數對應的信號名,handler的取指:常數SIG_IGN、常數SIG_DFL或接到此信號後要調用的函數的地址。若是指定SIG_IGN,則向內核表示忽略此信號(SIGKILL SIGSTOP不能忽略),若是指定SIG_DFL表示接收到此信號後的動做是系統默認動做。當指定函數地址時,我稱此爲捕捉此信號,成函數爲信號處理程序或信號捕捉函數。
signal函數有兩個參數,返回一個函數指針,signum是一個整型數,第二個參數是函數指針,它指向的函數須要一個整形參數,無返回值。
<signal.h>中 #deifne SIG_ERR -1 #define SIG_DFL 0 #define SIG_IGN 1
(2) sigaction函數
sigaction函數的功能是檢查或修改與指定信號相關聯的處理動做,此函數能夠徹底替代signal函數,sigaction函數以下:
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
返回:成功返回0,出錯返回-1.
signum是要捕捉的信號。act是一個結構體,裏邊包含了信號處理函數的地址、處理方式等信息。參數oldact是一個傳出參數,sigaction調用成功後,oldact裏邊包含之前對signum信號的處理方式的信息。
struct sigaction
{
void(*sa_hanlder)(int)
void (*sa_sigaction)(int,siginfo_t *,void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restore)(void);
}
字段sa_handler是一個函數指針,用於指向原型爲void handler(int)的信號處理函數地址,即老類型的信號處理函數。
字段sa_sigaciton是一個函數指針,指向void handler(int iSignNum,siginfo_t *pSiginfo,void *pReserved);的信號處理函數,新類型信號處理函數。該函數三個參數意義: iSigNum傳入的信號,pSiginfo與該信號相關的一些信息,是個結構體。pReserve的,保留。
字段sa_handler sa_sigaction應該只有一個有效,若是用老信號處理機制,讓sa_handler指向正確的函數,若是用新的信號處理機制,讓sa_sigaction指向正確處理函數,並讓sa_flags包含SA_SIGINFO選項。
sa_mask是一個包含信號集合的結構體,表示被阻塞的信號。
(3)信號集
爲了方便同時對多個信號進行處理,Linux系統中引入了信號集的概念。 信號集用於表示多個信號所組成集合的數據類型,信號集定義爲sigset_t類型的變量,5個處理信號集的函數:
#include <signal.h>
int sigemptyset(sigset_t *set); 將set指向的信號集設定爲空,不包含任何信號。
int sigfillset(sigset_t *set); 將set指定的信號集設定爲滿,即包含全部信號。
int sigaddset(sigset_t *set,int signum); 將signum所表明的信號添加到set指定的信號集。
int sigdelset(sigset_t *set,int signum); 將signum表明的信號從set信號集中刪除。
返回:成功返回0,錯誤返回-1.
#include <signal.h>
int sigismember(const sigset_t *set,int signum); 檢查signum表明的信號是否存在於set信號集中。
返回:若爲真返回1,爲假返回0.
set 指向信號集的指針,signum表示一個信號。
(4) 信號的發送
發送信號函數:kill raise sigque alarm setitimer abort 。
kill 函數用於向某一給定進程或進程組發送信號,函數以下:
#include <signal.h>
#include <sys/types.h>
int kill(pid_t pid, int signum); 返回:成功返回0,出錯返回-1.
pid表示進程或進程組的編號,signum發送的信號。若是signum0 能夠檢查進程是否存在。
raise 函數用於向進程自己發送信號,函數以下:
#include <signal.h>
#include <sys/types.h>
int raise(int signum); 返回:0成功, -1 錯誤。
sigqueue函數
sigqueue函數是針對實時信號提出的,支持信號帶有參數,一般與函數sigaction配合使用,函數以下:
#include <signal.h>
#include <unistd.h>
int sigqueue(pid_t pid,int signum,const union sigval val); 若成功返回0,出錯返回-1.
pid是指定信號的進程ID,signum 將發送的信號,union signal 是一個聯合數據結構,指定了信號傳遞的參數,即4字節值,定義以下:
typedef union sigval
{
int sival int;
void *sigval_ptr;
} sigval_t;
sigqueue比kill傳遞了跟多的附加信息,單sigqueue只能向一個進程發送信號,而不能發送信號給一個進程組。若是signum=0將會執行錯誤檢查,但實際上不發送任何信號,
十8、進程間通訊
進程間通訊(InterProgress Communication,IPC)就是在不一樣進程之間傳播或交換信息。進程的空間是相互獨立的,按說是不能相互訪問,惟一的例外是共享內存區,內核能夠提供共享內存的條件。
Linux的進程間通訊的方法有管道、消息隊列、信號量、共享內存區、套接口等。管道分爲命名管道、無名管道。消息隊列、信號量、共享內存成爲系統IPC。管道、消息隊列、信號量和共享內存用於本地進程間的通訊,套接口用於遠程進程間通訊。
管道(pipe)及命名管道(named pipe):管道用於親緣關係進程間的通訊,命名管道克服了管道沒有名字的限制,除具備管道的全部功能外,還用於無親緣關係進程間的通訊。
進程間通訊就是讓多個進程之間相互訪問,這種訪問包括程序運行時適時的數據,也包括對方的代碼段。
18.一、管道
管道(pipe)也叫匿名管道,是在兩個進程之間實現一個數據流通的通道。至關於文件系統上的一個文件,來緩存所須要的數據。略區別於文件,管道中的數據讀出後,管道中就沒有數據了。管道會隨着進程的結束而被系統清除,建立一個管道時生成兩個文件描述符,對於管道所使用的文件描述符並無路徑名。常用|來連接連個命令。
管道從數據流上全雙工管道和半雙工管道,管道沒有命名的成爲匿名管道,管道是半雙工的,數據只能向一個方向流動。只能用於父子進程和兄弟進程之間。單獨構成一個獨立的文件系統。數據的讀出和寫入。管道的緩衝區是有限制的。管道傳送的是無格式字節流,要求管道的讀出和寫入房必須事先約定好數據格式。
Linux下使用pipe函數建立一個匿名管道,函數原型以下:
#include <unistd.h>
int pipe(int fd[2]);
返回:若成功則返回0,若出錯則返回-1.
參數fd[2]是個長度爲2的文件描述符組,fd[0]是讀出端的文件描述符,fd[1]是寫入段的文件描述符。函數成功返回後,則自動維護一個從fd[1]到 fd[0]的數據管道。管道的關閉則使用基於文件描述符的close函數。
能夠使用read和write函數對管道進行操做,管道的讀出端只能讀數據管道的輸入端只能輸入數據,若是從輸入端讀或者從輸出端寫都會出錯,通常的IO操做函數均可以用於管道,open close write read等。
對一個讀端已經關閉的管道進程操做是,會產生SIGPIPE,說明管道讀端已經關閉,而且write操做返回-1,error值設爲EPIPE,對於SIGPIPE信號進行捕捉處理。
若是要創建一個父進程到子進程的數據通道,能夠先調用pipe函數緊接着調用fork函數,因爲子進程會自動繼承父進程的數據段,則父子進程同時擁有管道的操做權,管道的方向取決於用戶怎麼維護該管道。
要創建一個父進程到子進程的數據通道,也就是在子進程讀出以前在父進程中寫入數據,那麼要在父進程中關閉管道的輸出端,相應的在父進程中關閉管道的寫入端,當維護子進程到父進程的數據通道時,父進程中關閉寫入端,子進程中關閉讀出端。使用pipe及fork組合,能夠構造全部的父進程與子進程或子進程到兄弟進程的管道。
(2) 命名管道
命名管道也成爲FIFO,它是一種文件類型,在文件系統中能夠找到它,建立一個FIFO相似於建立一個文件。在程序中能夠經過查看文件stat結構體中的st_mode成員的值來判斷該文件是否爲FIFO。即便不存在親緣關係的進程也能夠經過FIFO中路徑名進行交互。
FIFO遵照先進先出的規則,對管道及FIFO的讀老是從開始處返回數據,對它們寫則把數據添加到末尾,不支持Sleek等文件定位操做。shell中能夠使用mkfifo命令創建一個命名管道, mkfifo [option] name ... option選擇中選擇要建立FIFO的模式,使用形式爲 -m mode,這裏的mode指出將要建立FIFO的八進制模式。
建立FIFO相似於建立一個普通文件,FIFO文件能夠經過文件名來訪問,函數原型以下:
#include<sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
返回:成功返回0,錯誤返回-1.
第一個參數路徑名,也就是FIFO文件的名字,第二個參數與open函數中的mode參數相同。若是mkfifo的第一個參數是一個已經存在的路徑名時,則返回EEXIST錯誤,典型的調用會先判斷是否返回該錯誤,若是返回,則直接打開FIFO就能夠了。FIFO文件隱形的規定不具備執行權限。
(3) 命名管道的讀寫
系統調用open打開一個命名管道,使用read和write函數對命名管道進行讀寫,close關閉一個管道,unlink刪除一個命名管道。
(4) 消息隊列
消息隊列是一種以鏈表式結構組織的一組數據,存放在內核中,由各進程經過消息隊列標識符來引用。管道是隨進程持續的,消息隊列是隨內核持續的。
消息隊列類型:POSIX消息隊列及System V 消息隊列,System 消息隊列目前被大量使用。system V消息隊列是隨內核持續的,只有在內核重啓或者顯示刪除一個消息隊列時,該消息隊列纔會真正刪除。系統中記錄消息隊列的數據結構(struct ipc_ids msg_ids)位於內核中,消息中全部消息對壘均可以在結構msg_ids中找到訪問入口。
消息隊列就是一個消息的鏈表。每一個消息隊列都有一個隊列頭,用結構struct msg_queue來描述,隊列頭包含了消息隊列鍵值、用戶ID、組ID、消息隊列中消息數目等。
(1) 消息隊列的建立與打開
消息隊列的內核持續性要求每一個消息隊列在系統範圍內都對應惟一的鍵值,要得到一個消息隊列的引用標識符(ID)----即建立或打開消息隊列,只須要提供該消息的鍵值便可。
得到特定文件名的鍵值的系統調用是ftok,函數以下:
#include <sys/types.h>
#include <sys/ipc.h>
key_t tfok (char *pathname,char proj);
返回:若成功則返回一個消息隊列的鍵值,若失敗則返回-1. 該函數並不直接對消息隊列進行操做,但在調用msgget() 函數得到消息隊列標識符前,調用該函數。
建立或打開一個消息隊列的系統調用爲msgget,函數原型以下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key,int msgflag);
返回:若成功則爲消息隊列的引用標識符(ID),若失敗則返回-1. 參數key是一個鍵值,由ftok得到,msgflg參數是一些標誌位,能夠取下值:IPC_CREAT、IPC_EXCL/IPC_NOWAIT或三者的邏輯或結果。
如下狀況將會建立一個新的消息隊列:
若是沒有消息隊列與鍵值key相對應,而且msgflg包含了IPC_CREAT標誌位。
key參數爲IPC_PRIVATE (設置成該標誌並非其餘進程不能訪問該消息隊列,只意味着將建立新的消息隊列。)
(2) 消息隊列的讀寫
使用消息隊列進行進程間通訊,要對消息隊列進行讀和寫的操做,寫操做即向消息隊列中發送數據,讀操做即從消息隊列中讀出數據。
消息隊列由兩部分組成:消息類型和所傳遞數據,用數據結構struct msgbuf 來表示,消息類型一般是一個長整數。設定一個傳遞1024個字節長度的消息,可將結構定義以下:
struct msgbuf
{
long msgtype; // 消息類型,消息隊列中讀取消息的依據
char msgtext[1024]; // 消息內容,大小可調整
}
對於發送消息,首先預製一個msgbuf緩衝區並寫入消息類型,調用響應的發送函數便可;對讀消息來講,首先分配一個msgbuf緩衝區,把消息讀入緩衝區便可。
向消息隊列發送數據;
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid,const void *prt,size_t nbytes,int flags);
返回:若成功返回0,出錯返回-1.
msgsnd向一個消息隊列發送一個消息,該消息被追加到隊列的末尾。msgid表明隊列的標識符,prt指向要發送的消息,nbytes 數據長度,flags用於指定消息隊列滿時的處理方法。對於發消息來講,有意義的flags標誌位IPC_NOWAIT,指明在消息隊列沒有足夠空間發送消息時,msgsnd是否等待。當消息隊列滿時,若是設置了IPC_NOWAIT位,則馬上出錯返回,不然發送消息的進程被阻塞,直至消息隊列中有空間或消息隊列被刪除時,函數馬上返回。
形成msgsnd等待的條件有兩種: 當前的大小與消息隊列中的字節個數超過消息隊列的總容量。 消息隊列中的消息數不小於消息隊列的總容量。
msgsnd 解除阻塞的條件有3個:不知足上述兩個條件。msqid表明的消息隊列被刪除。調用msgsnd的進程被某個信號中斷。
從消息隊列中接收數據,函數原型:
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
int msgrcv(int msqid,void *prt ,size_t nbytes,long type ,int flags);
返回:成功返回消息的數據長度,若出錯則返回-1.
此函數用於從指定消息隊列中讀取一個消息數據。msqid表明消息隊列的引用標識符,prt 緩衝區,nbytes 字節個數,flags消息隊列滿時的處理方法。
得到或設置消息隊列的屬性:
消息隊列的信息基本上都保存在消息隊列頭中,分配一個相似於消息隊列頭結構struct msqid_ds來返回消息隊列屬性;keil設置該數據結構,函數以下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid,int cmd ,struct msqid_ds *buf);
返回:成功返回0,不然返回-1.
系統調用對由msgid表示的消息隊列執行cmd操做,cmd操做有三種:IPC_STAT IPC_SET IPCRMID.
IPC_STAT:用來獲取隊列消息,返回的信息存貯在buf指向的msqid_ds結構中。
IPC_SET : 該命令用設置消息隊列屬性,屬性包括msg_perm.uid msg_perm.pid msg_perm.mode msg_qbytes同時影響msg_ctime 成員。
IPC_RMID:刪除msqid消息隊列。
18.五、共享內存
共享內存是linux下最快速最有效的進程間通訊方式。兩個不一樣進程A、B共享內存的意思是,同一物理內存被映射到進程A、B各自的進程地址空間。進程A能夠即時看到進程B對共享內存數據的更新,反之B也能夠看到A。
二10、網絡編程
OSI七層模型是設計和描述網絡通訊的基本框架,描述了網絡硬件和軟件若是以層的方式協同工做進行網絡通訊。
(1)物理層
物理層並非指物理設備或屋裏媒體,而是有關物理設備經過屋裏媒體進行互聯的描述和規定,物理層定義了接口的機械特性、電氣特性、功能特性、規程特性等。
物理層以比特流的方式傳送來自數據鏈路層的數據,不理會數據的格式和含義,它接收數據後直接傳給數據鏈路層,物理層只能看到0和1.
(2) 數據鏈路層
數據鏈路層是OSI模型的第二層,負責從一臺計算機到另外一臺計算機無差錯的傳輸數據幀,容許網絡層經過網絡鏈接進行虛擬的無差錯傳輸。
一般,數據鏈路層發送一個數據幀後,等待接收方確認。接收方 數據鏈路層檢測幀傳輸過程當中產生的任何問題,沒有通過確認和損壞的幀都要進行重傳。
(3) 網絡層
負責信息地址和將邏輯地址與名字轉換爲物理地址。
網絡層,數據傳送的單位是包。網絡層的任務是選擇合適的路徑和轉發數據包,使發送方數據包可以正確的按照地址尋找到接收方的路徑,並將數據包交給接收方。網絡層負責最佳路徑的選擇。
網絡層向傳輸成提供服務,同時將網絡地址翻譯成物理地址,還能協調發送、傳輸及接收設備能力不平衡的問題,網絡層對數據進行分段和重組。
(4) 傳輸層
保證在不一樣子網的兩臺設備之間數據包可靠、順序、無差錯的 傳輸。傳輸層數據傳輸的單位是段。傳輸層負責端到端通訊(一臺計算機到另外一臺計算機),中間能夠有一個或多個交換節點。
傳輸層主要功能是將接收到的亂序數據包重新排序,並驗證全部的分組是否已被接收到。
(5) 會話層
會話層是利用傳輸層提供的端到端的服務,向表示層或會話用戶提供會話服務。會話層的功能是在兩個節點間創建、維護和釋放面向用戶的連接,並對會話進行管理和控制,保證會話數據可靠傳送。
會話鏈接和傳輸鏈接的三種關係:一對一關係,一個會話鏈接對應一個傳輸關係,一對多,一個會話鏈接對應多個傳輸關係;多對一關係,多個會話鏈接對應一個傳輸關係。
會話層協議有結構化查詢語言SQL、遠程進程呼叫RPC、Xwindows系統、AppleTalk會話協議、數字網絡結構會話控制協議DNA SCP等。
(6) 表示層
表示層如下各層主要負責數據在網絡傳輸時不會出錯,可是數據傳輸沒有錯不表明數據所表示的信息沒有錯。表示層專門負責有關網絡計算機信息表示方式問題。
(7) 應用層
直接與用戶和應用程序打交道,負責對軟件提供接口使程序能使用網絡。應用層不僅爲OSI模型外的其餘應用程序提供服務。應用層協議:虛擬終端協議Telnet、簡單郵件傳輸協議SMTP、簡單網絡管理協議SNMP、域名服務系統DNS、超文本傳輸協議HTTP。
TCP/IP協議族中最重要的協議是傳輸控制協議TCP、網絡互連協議IP,TCP和IP負責管理和引導數據報在Internet上的傳輸,TCP負責和遠程主機的鏈接,IP負責尋址,使報文被送到目的地。
(1) 網絡接口層協議
TCP/IP網絡接口層中包括各類無力層協議,如以太網、令牌環、幀中繼、ISDN和分組交換網X.25。
(2) 網絡層協議
網絡層包括多個重要協議:有4個主要協議好比IP協議、ARP協議、RARP協議和ICMP協議。
IP協議:規定網際協議層數據報分組的格式。
ICMP因特網控制消息協議:提供網絡控制和消息傳遞功能。
ARP地址解析協議:將邏輯地址解析成物理地址。
RARP反地址解析:經過RARP廣播將物理地址解析成邏輯地址。
(3)傳輸層協議
主要有TCP和UDP協議,基於套接字的網絡編程,是基於這兩個協議實現的。
傳輸控制協議TCP:TCP是面向鏈接的協議,用三次握手和滑動窗口機制來保證傳輸的可靠性和進行流量控制。
用戶數據報協議UDP:面向無鏈接不可靠的傳輸。
(1) 傳輸控制協議TCP
TCP和UDP最大區別是TCP是面向鏈接的,UDP是面向無鏈接的。
TCP協議採用許多機制保證端到端節點之間的可靠數據傳輸,如採用序列號、確認重傳、滑動窗口等。
首先,TCP爲所發送的每個報文段加上序列號,保證每個報文段能被接收方接收並只被正確的接收一次。
其次,TCP採用具備重傳功能的積極確認技術做爲可靠數據流傳輸服務的基礎。確認指接收端在正確的接收到報文段以後向發送端返回一個確認(ACK)信息。發送方將每一個已發送的報文段備份在本身的發送緩衝區裏,並且在收到相應的確認以前不會丟棄所保存的報文段的。「積極」指發送方在每個報文段發送完畢的同時啓動一個定時器,假如定時器的定時期滿而關於報文段的確認信息還沒收到,則發送方任務該報文段已經丟失並主動重發。爲了不因爲網絡延遲引發的遲到確認和重複確認,TCP在每一個確認信息中捎帶一個報文段的序號,使接收方能正確的將報文段和確認聯繫起來。
最後,採用可變長的滑動窗口協議進行流量控制,防止因爲發送端與接收端之間的不匹配而引發數據丟失。
(2)TCP 連接的創建
TCP連接的創建包括創建鏈接、數據傳輸和拆除鏈接3個過程。 TCP經過TCP端口提供連接服務,最後經過鏈接服務來接收好而發送數據。TCP鏈接的申請、打開、關閉必須遵照TCP協議的規定。TCP使用三次握手來創建鏈接,連接能夠由任一一方發起,也能夠同時發起。一臺主機上的TCP軟件主動發起鏈接請求,另外一臺主機上的TCP軟件只能被動的等待握手。
三次握手:
① 源主機A的TCP向目的主機B發出鏈接請求報文段,首部中的SYN(同步)標誌位應置爲1,表示想與目標主機B進行通訊,併發送一個同步序列號X(例 SEQ=100)進行同步,表示在後面數據傳送時第一個數據字節的序列號是X+1(101).
② 目標主機B的TCP收到鏈接請求報文後,如贊成,則發回確認,在報文中將ACK位和SYN位置1.確認號爲X+1,同時也爲本身選擇一個序列號Y。
③ 源主機A的TCP收到目標主機的確認後想目標主機B給出確認,其ACK置爲1,確認號Y+1,而本身的序號爲X+1。TCP標準規定,SYN置1的報文段要消耗掉一個序號。
連接創建,源主機A向主機B發送第一個數據報文段時,其序號讓爲X+1,由於前一個確認報文段並不消耗序號。
TCP鏈接創建後,能夠發送數據,數據發送結束,須要關閉連接,鏈接的關閉必須由通訊雙方共同完成。通訊的一方沒有數據須要發送給對方時,能夠使用FIN段向對方發送關閉鏈接請求。雖然不在發送數據,但不排斥在這個鏈接上繼續接受數據,只有當通訊的對方也遞交了關閉鏈接的請求後,TCP鏈接才徹底關閉。
(3) 用戶數據報協議UDP
UDP在傳送數據以前不須要創建鏈接,對方的傳輸層在收到UDP報文後,不須要給出確認信號。
UDP協議特色:在UDP傳送前不須要創建鏈接,傳輸前發送方和接收方相互交換信息使雙方同步;UDP不對收到的數據進行排序,UDP報文中沒有關於數據順序的信息(TCP的序號),並且報文不必定是順序到達;UDP對接收到的數據報不發送確認信號,發送端不知道數據是否被正確接收,也不會重發數據;UDP比TCP傳輸快。
(4) 客戶機/服務器模式(C/S模式)
要求每一個應用程序有兩個部分組成:一個部分負責啓動通訊,另外一個部分負責對它進行應答。
20.二、套接口編程
套接口是操做系統內核的一個數據結構,是網絡中節點進行通訊的門戶。網絡編程也稱爲套接口編程。
套接口也就是網絡進程的ID,網絡通訊歸根究竟是進程間的通訊。網絡中,每個節點(計算機或路由器)都有一個網絡地址即IP地址,兩個進程通訊時,首先要肯定各自所在網絡節點的網絡地址,可是網絡地址只能肯定所在的計算機,一臺計算機上可能同時運行着多個進程,因此還須要端口號進一步肯定和哪一個進程通訊。一臺計算機上,一個端口號一次只能分配給一個進程,進程和端口號是一一對應的。
網絡地址和端口號信息放在一個結構體中,組成套接口的地址結構,大多數套接口函數都須要指向一個套接口地址結構的指針做爲參數,以此來傳遞信息,每一個協議族都定義了本身的套接口地址結構,套接口地址結構以
sockaddr_開頭。
套接口三種類型:流式套接口(TCP套接口 SOCK_STREAM)、數據報套接口(UDP套接口 SOCK_DGRAM)、原始套接口(SOCK_RAW)。
網絡技術中,端口有2中意思:一是物理端口,二是邏輯意義上的端口,通常指TCP/IP 協議中的端口,範圍從0~65535.端口分爲兩類:一類是固定通用的端口,數值爲0~1024,另外一類是通常端口,用來隨時分配給請求通訊的客戶進程。
套接口的數據結構
在bind、connect等系統調用中,特定於協議的套接口地址結構指針都要強制轉換成該通用的套接口地址結構指針,通用套接口數據接口在sys/socket.h 中,以下:
struct sockaddr
{
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
}
IPv4套接口地址數據結構:
IPv4套接口地址數據結構以socketaddr_in命名,在netinet/in.h中,以下:
struct socketaddr_in
{
uint8_t sin_len; // 數據長度成員,通常不設置
sa_family_t sin_fanmily ; // 套接口結構地址族,IPv4爲AF_INET
in_port_t sin_port; // 16位端口號。
strtct in_addr sin_addr; // 32位的IP地址
unsigned char sin_zero[8]; // 未用
}
struct in_addr
{
in_addr_t s_addr; //32位的IP地址。
}
20.三、基本函數
(1) 字節排序函數
計算存儲方式分爲大端模式、小段模式。端口號和IP地址都是以網絡字節順序存儲的,網絡字節順序使用的是大端模式。某個系統所用是本身順序爲主機字節序。主機字節序和網絡字節序的排序函數:
#include <netinet/in.h>
uint32_t htonl(uint32_t hostlogn);
uint16_t htons(uint16_t hostshort);
返回的是網絡字節。
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
返回的是主機字節。
4個轉換函數中,h表明host,n表明network,s表明short,l表明long。
(2) 字節操縱函數
套接口編程中,須要一塊兒操縱結構體中的某幾個字節,字節操縱函數以下:
#include <string.h>
void bzero(void *dest,size_t nbytes); // 從dest指定地址開始的n個字節設置爲0
void bcopy(const void *src,void *dest,size_t nbytes); // 複製函數
int bcmp(const void *ptrl,const void *ptr2,size_t nbytes);
void memset(void *dest,int c,size_t len);
void memcpy(void *dest,const void *src,size_t nbytes);
int memcmp(const void *ptrl,const void *ptrl,size_t nytes);
以b打頭的函數有系統提供,以mem開頭的由ANSI C提供。
(3) IP地址轉換函數
TCP/IP網絡上,用的IP都是以‘.’隔開的十進制數表示,套接口的數據結構中用的是32位的網絡字節順序的二進制數值,轉換函數以下:
#include <arpa/inet.h>
int inet_aton(const char *straddr,struct in_addr *addrptr);
返回:轉換成功返回1,不成功返回0.
將點分十進制IP地址轉換爲網絡字節序的32位二級制數值。輸入的點分十進制放在參數straddr中,返回二進制數值放在addrptr中。
char *inet_ntoa(struct in_addr inaddr);
返回:若成功則返回點分十進制數串的指針,失敗返回NULL。
調用結果做爲函數的返回值返回給調用它的函數。
int_addr_t inet_addr(const char *straddr);
返回:成功返回32位二進制的網絡字節序地址,出錯返回INADDR_NONE。
(4) IP和域名的轉換
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
實現域名或主機名到IP地址的轉換,hostname指向存放域名或主機名的字符。
struct hostent *gethostbyaddr(const char *addr,size_t len ,int family);
實現IP地址到主機名或域名的轉換。addr指向一個含有地質結構(in_addr)的指針,len是結構大小,對於IPV4 是4,IPv6值爲16.
返回:成功返回hosten指着,失敗返回NULL,同時設置全局變量h_errno爲相應的值。h_errno值以下:
HOST_NOT_FOND主機沒找到,TRY_AGNAIN出錯重試,NO_RECOVERY不可修復性錯誤,NO_DATA指定的名字有效但沒有記錄。
結構體struct hostent定義:
struct hostent
{
char *h_name ; // 主機的正式名稱
char *h_aliases; // 主機的別名
int h_addrtype; // 主機的地址類型
int h_length; // 主機的地址長度
char **h_addr_list; // 主機的IP地址列表
}
20.三、TCP套接口編程
大體工做流程:
(1) 服務器用soket()函數創建一個套接口,用這個套接口完成通訊的監聽及數據收發。
(2) 服務器用bind()函數來綁定一個端口號和IP地址,使套接口與指定的IP和端口相連。
(3) 服務器調用listen()函數,使服務器的這個端口和IP處於監聽狀態,等待網絡中客戶機的鏈接。
(4) 客戶機用socket()函數創建一個套接口,設定遠程IP和端口號
(5) 客戶機用connect()函數鏈接遠程計算機的端口
(6) 服務器調用accept()函數來接收遠程計算機的鏈接請求,創建與客戶機通訊鏈接。
(7) 創建鏈接後,客戶機用write()函數(或send()函數)向socket中寫入數據。也能夠用read()函數(或recv()函數)讀取服務器發來的數據。
(8) 服務器用(7)的函數來接收和發送數據。
(9) 完成通訊後,使用close()關閉socket鏈接。
建立套接口:
系統調用socket生成一個套接口描述符,函數以下:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int family,int type,int protocol);
若成功返回套接口描述符,若失敗返回-1.
參數family指明協議族,PF_UNIX(UNIX協議族)、PF_INET(IPv4協議)、PF_INET6(IPv6協議)、AF_ROUTE(路由套接口)等,type指明通訊字節流類型:SOCK_STAREAM(TCP方式)、SOCK_DGRAM(UDP方式)、SOCK_RAW(原始套接口)、SOCK_PACKET(支持數據鏈路訪問)等,參數protocol可設置爲0。
socket系統調用爲套接口在sockfs文件系統中分配一個新的文件和dentry對象,並經過文件描述符把它們與調用進程聯繫起來,進程能夠像訪問一個文件同樣訪問套接口在sockfs中對應的文件。進程不能用open()來訪問該文件。
綁定端口
socket函數創建一個套接口後,須要使用bind函數在這個套接口上綁定一個指定端口和IP地址,函數以下:
#include <sys/types.h>
#incldue <sys/socket.h>
int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
返回:成功返回0,失敗返回-1.
參數sockfd表示已經創建的socket描述符,my_addr sockaddr類型的指針,addrlen 表示myaddr的長度。
等待監聽函數
socket的端口一直處於等待狀態,監聽網絡中全部的客戶機,耐心等待某一個客戶機的發送請求,若是有鏈接請求,端口就會接受這個鏈接,函數以下:
#include <sys/socket.h>
int listen(int sockfd,int backlog);
返回:成功返回0,失敗返回-1
sockfd表示已經創建的套接口,backlog表示同時處理的最大鏈接請求數目。listen並未真正的創建鏈接,真正接受客戶端鏈接的是accept();一般listen函數在socket() bind() 以後調用,而後調用accept();
listen 函數只適用於SOCK_STREAM SOCK_DGRAM的socket類型,若是socket爲AF_INET,在backlog最大設爲128.
接受鏈接函數
若是某個時刻有客戶機請求,並非理解處理這個請求,而是將這個請求放入等待隊列中,系統空閒時處理請求,函數accept() 以下:
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd,sturct sockaddr *addr,socklen_t *addrlen);
返回:成功返回新的套接口描述符,失敗返回0.
參數sockfd表示層處於監聽狀態的socket,addr是一個sockaddr類型結構體類型指針,系統會把遠程主機的信息保存到這個結構體,addrlen 表示sockaddr的內存長度。
當addr接受一個連接時,會返回一個新的sock描述符,之後的數據傳輸和讀取經過新的sock編號來處理。
請求鏈接函數
所謂請求鏈接,指在客戶機向服務器發送信息以前,須要先發送一個鏈接請求,請求與服務器創建TCP通訊鏈接,connect函數完成這項功能,函數以下:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *serv_addr,int addrlen);
返回:成功返回0,失敗返回-1.
參數sockfd表示已經創建的socket,serv_addr結構體來存儲遠程服務器的IP與端口信息,addrlen表示sockaddr結構體的長度。
connect函數將本地的socket鏈接到serv_addr指定的服務器IP與端口號上去。
數據發送函數
創建完套接口並鏈接到遠程主機上之後,能夠把信息發送到遠程主機上,而對於遠程主機發送來的信息,本地主機須要進行接收處理。
用connect函數鏈接到遠程計算機後,能夠用send函數將信息發送到對方的計算機,對方也能夠用send函數將應答信息發送到本地計算機,send函數以下:
#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd,const void *msg,int len,unsigned int flags);
返回:成功返回已發送的字符數,失敗返回-1.
flags通常設置爲0.
數據接收函數recv以下:
#include <sys/types.h>
#include <sys.socket.h>
int recv(int sockfd,void *buf,int len ,unsinged int flags);
返回:成功返回接收到的字節數,失敗返回-1.
(8) write與read函數
當socket鏈接創建之後,向這個socket中寫入數據即表示想遠程主機中傳送數據,從socket中讀數據則至關於從遠程主機中接收數據。read和write函數在socket編程中和send recv函數功能相似。
#include <unistd.h>
ssize_t read(int fd,const char *buf);
ssize_t write(int fd,const char *buf,size_t count);
20.四、UDP套接口編程
UDP是一個無鏈接不可靠的傳輸層服務,域名服務系統DNS,網絡文件系統NFS使用的是UDP鏈接。
TCP套接字必須先創建鏈接(客戶端connect請求鏈接,服務器listen()和accept()),而UDP不須要創建鏈接,它在電泳socket生成一個套接字後,在服務器端用bind綁定一個端口和IP,而後服務器進程掛起與recvfrom()調用,等待某一個客戶機的請求,客戶機sendto()請求一樣掛起與recvfrom()調用,等待並接受服務器應答信號,數據完成後客戶端調用close()釋放通訊鏈路。
數據發送函數sendto,至關於TCP鏈接中的send()或write函數,sendto函數以下:
int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *toaddr,int *addrlen);
數據接收函數recvfrom至關於TCP中的read 或recv函數。以下:
#include <sys/socket.h>
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *fromaddr,int *addrlen);
20、5 原始套接口
有三種套接字:SOCK_STREAM SOCK_DGRAM SOCK_RAW ,原始套接口只能有root權限的用戶建立,原始套接字有以下特色:
① 使用原始的套接口能夠讀寫ICMP(互聯網控制消息協議)及ICMPv6分組。
② 原始套接字能夠讀寫特殊的IP數據包,內核不處理這些數據包的IP協議字段,而出錯的診斷將依靠協議字段的意義。
③ 利用原始套接字經過設置IP_HDRINCL套接口選項建造本身的IP頭部。
原始套接口的建立
int sockfd;
sockfd=socket(AF_INET,SOCK_RAW,protocol);
TCP套接字和UDP套接口的protocol爲0,原始套接字的protocol取指能夠是IPPROTO_ICMP IPPROTO_TCP IPPROTO_UDP等,不一樣類型協議建立不一樣的原始套接字。
二11、圖形界面編程
圖形用戶界面(Graphical user interface)簡稱GUI,是指採用圖形的方式顯示的計算機操做用戶界面。GUI的組成部分包括桌面、視窗、單一文件界面、多文件界面、標籤、菜單、圖表、按鈕等。用來進行圖形用戶界面編程的工具(庫)成爲GUI工具包(GUI庫),GUI庫是構造圖形界面所使用的一套按鈕、滾動條、菜單和其餘對象集合。可供使用的GUI庫,如Motif、Qt、GTK+等,最經常使用的是GTK+ 和Qt。
21.一、窗口
窗口是一個應用程序的框架,程序的全部內容與用戶的交互都在這個窗口中,設置應用程序界面時第一步是創建一個窗口。gtk_window_new()函數創建一個GTK+窗口,函數以下:
#include <gtk/gtk.h>
GtkWidget *gtk_window_new(Gtk WindowType type);
返回:若成功,返回一個GTKWidget類型的指針,失敗返回空指針NULL。參數type表示一個窗口狀態常量,可能的取值如下兩種:
GTK_WINDOW_TOPLEVEL:表示這個窗口是一個正常的窗口。窗口能夠最小化,在窗口管理中能夠看到這一窗口按鈕。窗口控制器至關於windows下的任務欄。
GTK_WINDOW_POPUP: 表示這個窗口是一個彈出式窗口,不能夠最小化。但這個窗口是一個獨立運行的程序,並非一個對話框。
gtk_window_new()函數的返回值是一個GtkWidget類型的指針,圖形界面的全部元素都會返回這個指針。GTKWidget結構體的定義:
typedef struct
{
GtkStyle *style; // 元件的風格
GtkRequisition requisition; // 元件的位置
GtkAllocation allocation; // 容許使用的空間
GtkWindow *window; // 元件所在的窗口或父窗口
GtkWidget *parent; // 元件的父窗口
}GtkWidget;
新建一個窗口之後,這個窗口不會立刻顯示出來,須要調用窗口顯示函數gtk_window_show()來顯示這個窗口,函數以下:
#include <gtk/gtk.h>
void gtk_window_show(GtkWidget *widget);
參數widget是一個GtkWidget類型的結構體指針,指向須要顯示的窗口。
設置窗口標題gtk_widnow_set_title()函數以下:
#include <gtk/gtk.h>
void gtk_window_set_title();
指針title所指向的字符串必須是英文字符的,但若是咱們想要顯示中文字符,使用g_locale_to_utf8()函數進行批註。
設置窗口的大小和位置
窗口的大小指的是窗口的寬度和高度,用gtk_widget_set_usize() 函數來設置一個窗口的初始大小。窗口的位置指的是窗口的左上角頂點到屏幕左邊和頂邊的距離,能夠用gtk_widget_set_uposition()函數來設置一個窗口的初始位置,函數下:
include <gtk/gtk.h>
void gtk_widget_set_usize(GtkWidget *widget,gint width,gint height);
void gtk_widget_set_position(GtkWidget *widget ,gint x,gin y);
標籤:
標籤是程序中的一個文本,這個文本能夠顯示必定的信息,用戶不能輸入和改變標籤內容,界面中的提示信息和顯示內容都是經過標籤來實現的。
新建一個標籤:
使用標籤以前,須要新建一個標籤,gtk_lable_new() 用來新建一個標籤,函數:
#include <gtk/gtk.h>
GtkWidget * gtk_lable_new(gchar *text);
返回:成功則返回一個GtkWidget的指針,若失敗則返回NULL。
參數text表示要顯示的內容,和窗體同樣,新建標籤後須要調用顯示函數gtk_widget_show()來顯示這個標籤,函數以下:
#include <gtk/gtk.h>
void gtk_widget_show(GtkWidget *lable);
參數label表示gtk_lable_new()新建的標籤,無返回值
將標籤添加到窗口:
GTK+窗口中,除了window窗口外,其餘的原件都必須放在一個容器中,例如新建的標籤不能直接顯示,須要放在一個容器中。gtk_container_add()函數的做用就是把一個元件放置在一個容器中,函數以下:
#include <gtk/gtk.h>
void gtk_container_add(GtkContaner *contaner,GtkWidget *widget);
container是一個父級的容器指針,widget是須要放置元件的指針。無返回值。
gkt_table_add()能夠將一個標籤添加到一個表格中,而後用gtk_container_add()將表格添加到窗口中。
設置和獲取標籤的文本
用gkt_lable_get_text()函數來獲取一個標籤的文本,使用gtk_lable_set_text()函數來設置一個標籤的文本,函數以下:
#include <gtk/gtk.h>
const char *gkt_lable_get_text(GtkLable *lable); 返回:成功返回標籤文本的字符串指針,失敗NULL
void gtk_lable_set_text(GtkLable *lable,gchar *text); 無返回值
lable 是一個指向標籤的指針,text表示標籤須要設置文本。
按鈕:
新建一個按鈕,函數:
GtkWidget * gtk_button_new(gchar *lable);
返回:若成功,返回一個GtkWidget 指針,失敗返回NULL。
新建成功後,調用gtk_widget_show()來顯示這個按鈕。
設置和獲取按鈕的標籤:
按鈕的標籤指的是按鈕上的文字,gtk_button_get_lable()獲取某個按鈕的標籤,函數gtk_button_set_lable();設置某個按鈕的標籤,函數以下:
#include <gtk/gtk.h>
const char *gtk_button_get_lable(GtkButton *button);
void gkt_button_set_lable(GtkButton *button ,const gchar *lable);
button指向按鈕的指針,lable ,按鈕標籤的內容。按鈕一般伴隨着一個事件。
文本框:
gtk_entry_new();函數來新建一個文本框,以下
GtkWidget * gtk_entry_new(void);
GtkWidget *gkt_entry_new_with_max_length(gint max);
兩個函數的做用同樣,max表示最多輸入的字符個數。
設置和獲取文本框內容
#include <gtk/gtk.h>
const char *gtk_entry_get_text(GtkEntry *entry);
void gtk_entry_set_text(GtkEntry entry ,const gchar *text);
GTK 是用utf8顯示的,所顯示的字符都須要utf8才能正常顯示,使用g_local_to_utf();函數來轉換,能夠使用中文。本地字符和utf8字符的轉換函數:
gchar * g_local_to_utf8(gchar *string,gssize len,gsize *bytes_read,gsize *bytes_written,GError **error);
gchar * g_local_from_utf8(gchar *string,gssize len,gsize *bytes_read,gsize *bytes_written,GError **error);
21.二、界面佈局元件
界面佈局元件包括表格、框、窗格等。表格是界面中最經常使用的元件,經過在單元格中插入不一樣元件來實現佈局和排列。若是一個元件中能夠放其餘的元件,這個元件叫容器。
表格的創建,函數以下:
#include <gtk/gtk.h>
GtkWidget *gtk_table_new(guint rows,guint columns,gboolean homogeneous);
參數rows表示行數,columns表示列數,homogeneous是一個布爾值,若是設置爲TURE則每一個單元格大小相同,若是設置爲FALSE則表格的大小會根據單元格中元件的大小自動調整。表格並不真正顯示,只是容納其餘元件和佈局用的。
將其餘元件添加到表格中,函數以下:
#include <gtk/gtk.h>
void gtk_table_attach(GtkTable *table ,GtkWidget *child,guint left_attach,guint right_attach,guint top_attach,guint bottom_attach,GtkAttachOptions xoption,GtkAttachOptions yoptions,guint xpadding,guint ypadding);
參數xoptions和yoptions 分別表示元件在表格中的 水平方向和垂直方向對其方式,xpadding,ypadding 分別表示元件與邊框水平方向和垂直方向的邊距。
GtkOptions的取值有三個:GTK_EXPAND元件以設置的大小顯示,若是大於容器的大小則容器自動變大,GTK_SHRINK 若是元件大於容器的大小,則自動縮小元件,GTK_FILL元件填充整個單元格。
嵌套表格:
設計複雜界面時,須要在一個表格中添加表格,實現表格嵌套,表格也是一個普通元件,能夠把一個表格添加到另外一個表格的單元格中。
22.三、信號與回調函數
圖形界面的程序是事件驅動的程序,程序進入gtk_main()函數後,等待事件的發生,一旦發生某個事件,相應的信號將產生,若是程序中定義了相應的消息處理函數(回調函數),系統會自動進行調用。
信號的做用是對某一個元件添加一個用戶交互的功能,g_signal_connect() 能夠把一個信號處理函數(回調函數)添加到一個元件上,在元件和處理函數間創建關聯,函數以下:
gulong g_signal_connect(GtkObject *object,gchar *name,Gcallback callback_func,gpointer func_data);
參數object是一個元件的指針,指向將產生信號的元件。name表示消息或時間的類型,一個按鈕的全部事件類型:activate 激活的時候發生,clicked 單擊之後發生,enter 鼠標指針進入這個按鈕之後發生,leave 鼠標離開這個按鈕之後發生,pressed 鼠標按下之後發生,released 鼠標釋放之後發生。
參數callback_func表示信號產生後將要執行的回調函數,func_data 傳遞給回調函數的數據。
函數的返回值用於區分一個元件的一個事件對應的多個回調函數,一個元件上能夠有不少個事件好比按鈕的單擊和雙機,每一個事件能夠有0個或多個處理函數。
(2) 回調函數
消息處理函數(回調函數)原型:
#include <gtk/gtk.h>
void callback_func(GtkWidget *gtkwidget,gpointer func_data);
參數gtkwidget指向要接收消息的元件,func_data指向消息產生時傳遞給該函數的數據。
附件:我遇到的問題及解決辦法(若是錯誤,深刻學習後再來修改)
一、安裝CH340驅動(源碼)
(1) 下載了CH340驅動的壓縮包.zip格式
(2) 用U盤拷貝到虛擬機的home目錄。
(3) unzip filename.zip 解壓縮文件,文件中包含了.c 文件 和makefile
(4) make 命令進行編譯
(5) apt install sl 命令進行安裝
源碼的安裝方式:
(1) 下載源碼包,根據壓縮包的類型使用相應的命令進行解壓縮
(2) 進入解壓縮後的目錄 執行 ./configure 命令檢查安裝環境(庫函數、頭文件),能夠指定安裝目錄,若是不指定默認在當前目錄。
(3) make 生成makefile 文件
(4) make install 進行安裝。
二、minicom安裝
ubuntu使用命令sudo apt-get install minicom 進行安裝,也能夠從光盤鏡像或者源碼安裝。
第一次配置使用root用戶權限使用命令:minicom -s 而後就能夠配置,配置完成後保存,在etc目錄下就有了minicom文件夾保存配置。
三、能夠用ls -l 或者ll 命令來查看目錄下各個文件的類型及讀寫執行權限,d開頭的是目錄文件,l開頭的是連接文件,_開頭的是普通文件,b開頭的是塊設備,c開頭的是字符設備。淺藍色的是目錄,綠色的是可執行文件。
chmod命令能夠改變目錄或文件的權限,好比chmod 755 a.txt 755分別表示擁有者、組、其餘用戶的權限,值按照r、w、x順序,容許就爲1,不容許爲0,好比rwxr-xr--權限就是754.
bin文件夾存放的是二進制文件,主要是用戶命令。
lib文件夾存放的是動態的連接庫。
(2)能夠去/sys/bus/usb-serial/drivers/ 查看USB轉串口設備以及設備號
四、shell的環境變量,PATH、HOME、HOSTNAME、LOGNAME、"echo $環境變量"顯示環境變量的信息。
臨時變量(自定義變量)使用export變成環境變量。
export PATH=/home/yang :$PATH ,添加環境變量並保持原來的,用來加載除了/lib和/usr/lib之外的其餘連接庫。
$引用變量。
五、Ubuntu 創建的sh文件,執行時不少狀況下須要修改文件的權限。
六、 .tar.xz 壓縮包的安裝
解壓安裝包: tar -vxf xxx.tar.gz
進入解壓後的包: cd xxx
配置編譯環境:./configure
進行編譯:make
安裝軟件:make install
七、Ubuntu下GTK+環境的安裝
先去/usr/include 目錄下看看有沒有gtk-2.0
安裝依賴關係:sudo apt-get install build-essential libgtk2.0-dev
編譯文件: gcc -o xxx -c xxx.c `pkg-config --cflags --libs gtk+-2.0`
注意:
.c文件的執行須要包括pkg的配置命令,不然會提示找不到gtk.h
符號「`」 上斜點的位置做在鍵盤esc鍵下邊 帶~號的鍵。