① linux網路 - 數據包在內核中接收和發送的過程(轉)
本文將介紹在Linux系統中, 數據包是如何一步一步從網卡傳到進程手中的 以及 數據包是如何一步一步從應用程序到網卡並最終發送出去的 。
如果英文沒有問題,強烈建議閱讀後面參考里的文章,裡面介紹的更詳細。
本文只討論乙太網的物理網卡,不涉及虛擬設備,並且以一個UDP包的接收過程作為示例.
網卡需要有驅動才能工作,驅動是載入到內核中的模塊,負責銜接網卡和內核的網路模塊,驅動在載入的時候將自己注冊進網路模塊,當相應的網卡收到數據包時,網路模塊會調用相應的驅動程序處理數據。
下圖展示了數據包(packet)如何進入內存,並被內核的網路模塊開始處理:
軟中斷會觸發內核網路模塊中的軟中斷處理函數,後續流程如下
由於是UDP包,所以第一步會進入IP層,然後一級一級的函數往下調:
應用層一般有兩種方式接收數據,一種是recvfrom函數阻塞在那裡等著數據來,這種情況下當socket收到通知後,recvfrom就會被喚醒,然後讀取接收隊列的數據;另一種是通過epoll或者select監聽相應的socket,當收到通知後,再調用recvfrom函數去讀取接收隊列的數據。兩種情況都能正常的接收到相應的數據包。
了解數據包的接收流程有助於幫助我們搞清楚我們可以在哪些地方監控和修改數據包,哪些情況下數據包可能被丟棄,為我們處理網路問題提供了一些參考,同時了解netfilter中相應鉤子的位置,對於了解iptables的用法有一定的幫助,同時也會幫助我們後續更好的理解Linux下的網路虛擬設備。
ndo_start_xmit會綁定到具體網卡驅動的相應函數,到這步之後,就歸網卡驅動管了,不同的網卡驅動有不同的處理方式,這里不做詳細介紹,其大概流程如下:
在網卡驅動發送數據包過程中,會有一些地方需要和netdevice子系統打交道,比如網卡的隊列滿了,需要告訴上層不要再發了,等隊列有空閑的時候,再通知上層接著發數據。
② linux系統上信號發送和信號接收講解
用於進程間通信,通信機制由操作系統保證,比較穩定。
在linux中可以通過kill -l查看所有信號的類型。
kill -信號類型 進程ID
int kill(pid_t pid, int sig);
入參pid :
pid > 0: 發送信號給指定的進程。
pid = 0: 發送信號給 與調用kill函數進程屬於同一進程組的所有進程。
pid < 0: 取|pid|發給對應進程組。
pid = -1:發送給進程有許可權發送的系統中所有進程。
sig :信號類型。
返回值 :成功:0;失敗:-1 (ID非法,信號非法,普通用戶殺init進程等權級問題),設置errno
以OpenHarmony源碼為例,應用ANR後,AbilityManagerService會通知應用mp堆棧信息,就是通過信號量做的。
頭文件位置 :
include <signal.h>
函數解釋 :
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
當接收到指定的信號signum時,就會跳轉到參數handler指定的函數執行。其中handler的入參是信號值。
函數原型 :
signum參數指出要捕獲的信號類型,act參數指定新的信號處理方式,oldact參數輸出先前信號的處理方式(如果不為NULL的話)。
sigaction結構體
sa_handler 信號處理函數
sa_mask 在處理該信號時可以暫時將sa_mask 指定的信號集擱置
sa_flags 指定一組修改信號行為的標志。 它由以下零個或多個的按位或組成
SA_RESETHAND:當調用信號處理函數時,將信號的處理函數重置為預設值SIG_DFL
SA_RESTART:如果信號中斷了進程的某個系統調用,則系統自動啟動該系統調用
SA_NODEFER :一般情況下, 當信號處理函數運行時,內核將阻塞該給定信號。但是如果設置了 SA_NODEFER標記, 那麼在該信號處理函數運行時,內核將不會阻塞該信號
sa_restorer 是一個替代的信號處理程序,當設置SA_SIGINFO時才會用它。
相關函數
int sigemptyset( sigset_t *set);
sigemptyset()用來將參數set信號集初始化並清空。
執行成功則返回0,如果有錯誤則返回-1。
完整示例