前言
linux的原始碼裡,網路介面的實現部份是非常值得一讀的,通過讀原始碼,不僅對網路協議會有更深的了解,也有助於在網路程式設計的時候,對應用函式有更精確的了解和把握。
本文把重點放在網路介面程式的總體結構上,希望能作為讀原始碼時一些指導性的文字。
本文以linux2.4.16核心作為講解的物件,核心原始碼可以在
如果你在linux啟動的時候有留意啟動的資訊, 或者在linux下打命令dmesg就可以看到這一段程式輸出的資訊:
ip protocols: icmp,udp,tcp,igmp也就是說現在陣列inet_protos裡面有了icmp,udp,tcp,igmp四個協議的inet_protocol資料結構,資料結構包含了它們接收資料的處理函式。
linux 2.4.16在linux/include/linux/socket.h裡定義了32種支援的bsdsocket協議,常見的有tcp/ip,ipx/spx,x.25等,而每種協議還提供不同的服務,例如tcp/ip協議通過tcp協議支援連線服務,而通過udp協議支援無連線服務,面對這麼多的協議,向使用者提供統一的介面是必要的,這種統一是通過socket來進行的。
在bsd socket網路程式設計的模式下,利用一系列的統一的函式來利用通訊的服務。例如乙個典型的利用tcp協議通訊程式是這樣:
sock_descriptor = socket(af_inet,sock_stream,0);
connect(sock_descriptor, 位址,) ;
send(sock_descriptor,」hello world」);
recv(sock_descriptor,buffer,1024,0);
第乙個函式指定了協議inet協議,即tcp/ip協議,同時是利用面向連線的服務,這樣就對應到tcp協議,以後的操作就是利用socket的標準函式進行的。
從上面我們可以看到兩個問題,首先socket層需要根據使用者指定的協議族(上面是af_inet)
從下面32種協議中選擇一種協議來完成使用者的要求,當協議族確定以後,還要把特定的服務對映到協議族下的具體協議,例如當使用者指定的是面向連線的服務時,inet協議族會對映到tcp協議。
從多個協議中選擇使用者指定的協議,並把具體的出理交給選中的協議,這和一起網路核心層向上和向下銜接的問題本質上是一樣的,所以解決的方法也是一樣的,同樣還是通過陣列。在linux/net/socket.c定義了這個陣列staticstruct net_proto_family *net_families[nproto] 。陣列的元素已經確定了,net_families[2] 是tcp/ip協議,net_families[3]
是x.25協議,具體那一項對應什麼協議,在include/linux/socket.h有定義。但是每一項的資料結構net_proto_family的ops是空的,也就是具體協議處理函式的位址是不知道的。協議的處理函式和ops建立聯絡是通過sock_register()(linux/net/socket.c)這個函式建立的,例如tcp/ip協議的是這樣建立關係的:
int __init inet_init(void) (net/ipv4/af_inet.c)
只要給出af_inet(在巨集裡定義是2),就可以找到net_failies[2] 裡面的處理函式了。
協議的對映完成了,現在要進行服務的映**。上層當然不可能知道下層的什麼協議能對應特定的服務,所以這種對映自然由協議族自己完成。在tcp/ip協議族裡,這種對映是通過struct
list_head inetsw[sock_max]( net/ipv4/af_inet.c)
這個陣列進行對映的,在談論這個陣列之前我們來看另外乙個陣列inetsw_array(net/ipv4/af_inet.c)
static struct inet_protosw inetsw_array =
, ,
}; 我們看到,sock_stream對映到了tcp協議,sock_dgram對映到了udp協議,sock_raw對映到了ip協議。現在只要把inetsw_array裡的三項新增到陣列inetsw[sock_max]就可以了,新增是通過函式inet_register_protosw()實現的。在inet_init()
(net/ipv4/af_inet.c) 裡完成了這些工作。
還有乙個需要對映的就是socket其它諸如accept,send(),
connect(),release(),bind()等的操作函式是怎麼對映的呢?我們來看一下上面的陣列的tcp的項
, 我們看到這種對映是通過ops,和prot來對映的,我們再來看看 tcp_prot這一項:
struct proto tcp_prot = ;
所以的對映都已經完成了,使用者呼叫connect()函式,其實就是呼叫了tcp_v4_connect()函式,按照這幅圖,讀起原始碼來就簡單了很多了。
六 socket層
上一節把socket層大多數要討論的東西都談論了,現在只講講socket 層和使用者的銜接。
系統呼叫socket(),bind(),connect(),accept,send(),release()等是在linux/net/socket.c裡面的實現的,系統呼叫實現的函式是相應的函式名加上sys_的字首。
現在看看當使用者呼叫socket()這個函式,到底下面發生了什麼。
socket(af_inet,sock_stream,0)呼叫了sys_socket(),sys_socket()接著呼叫socket_creat(),socket_creat()就要根據使用者提供的協議族引數在net_families裡尋找合適的協議族,如果協議族沒有被安裝就要請求安裝該協議族的模組,然後就呼叫該協議族的create()函式的處理控制代碼。根據引數af_inet,inet_creat()就被呼叫了,在inet_creat()根據服務型別在inetsw[sock_max]
選擇合適的協議,並把協議的操作集賦給socket就是了,根據sock_stream,tcp協議被選中,
inet_creat()
到此為止,上下都打通了
C語言寫的仿WINDOWS 介面計算器原始碼
define num0 0x5230 小鍵盤區上數字鍵0 define num1 0x4f31 小鍵盤區上數字鍵1 define num2 0x5032 小鍵盤區上數字鍵2 define num3 0x5133 小鍵盤區上數字鍵3 define num4 0x4b34 小鍵盤區上數字鍵4 defin...
Unix環境高階程式設計在linux下的原始碼配置
1.先去那個 downlowd apue 的tar.gz包,然後解壓至電腦中的某個目錄,比如我的是在 home user 下,然後進入解壓目錄apue.2e,修改make.defines.linux 中的wkdir home apue.2e,為wkdir home user apue.2e,這就是我...
linux之X介面下的「任務管理器」
一般來說,有 系統監視器 相當於windows下的 任務管理器 但是這兩個管理器在系統假死時都很難被調出來。linux這時候就有自己的優勢了。畢竟它有tty可以用。1,按ctrl alt f1 6。進入他任何乙個tty介面,輸入使用者名稱和密碼 經常有初學者鬧乙個笑話,說登入tty,無法輸入密碼。呵...