国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
linux網(wǎng)絡接口源碼的結(jié)構(gòu)
網(wǎng)絡接口源碼的結(jié)構(gòu)(一)
Linux最新穩(wěn)定內(nèi)核2.4.x的網(wǎng)絡接口源碼的結(jié)構(gòu)(一)
李元佳

一.前言
  Linux的源碼里,網(wǎng)絡接口的實現(xiàn)部份是非常值得一讀的,通過讀源碼,不僅對網(wǎng)絡協(xié)議會有更深的了解,也有助于在網(wǎng)絡編程的時候,對應用函數(shù)有更精確的了解和把握。本文把重點放在網(wǎng)絡接口程序的總體結(jié)構(gòu)上,希望能作為讀源碼時一些指導性的文字。

  本文以Linux2.4.16內(nèi)核作為講解的對象,內(nèi)核源碼可以在http://www.kernel.org上下載。我讀源碼時參考的是http://lxr.linux.no/這個交差參考的網(wǎng)站,我個人認為是一個很好的工具,如果有條件最好上這個網(wǎng)站。國內(nèi)http://211.71.69.201/joyfire/有類似

二.網(wǎng)絡接口程序的結(jié)構(gòu)
  Linux的網(wǎng)絡接口分為四部份:網(wǎng)絡設(shè)備接口部份,網(wǎng)絡接口核心部份,網(wǎng)絡協(xié)議族部份,以及網(wǎng)絡接口socket層。
  網(wǎng)絡設(shè)備接口部份主要負責從物理介質(zhì)接收和發(fā)送數(shù)據(jù)。實現(xiàn)的文件在linu/driver/net目錄下面。
  網(wǎng)絡接口核心部份是整個網(wǎng)絡接口的關(guān)鍵部位,它為網(wǎng)絡協(xié)議提供統(tǒng)一的發(fā)送接口,屏蔽各種各樣的物理介質(zhì),同時有負責把來自下層的包向合適的協(xié)議配送。它是網(wǎng)絡接口的中樞部份。它的主要實現(xiàn)文件在linux/net/core目錄下,其中l(wèi)inux/net/core/dev.c為主要管理文件。
  網(wǎng)絡協(xié)議族部份是各種具體協(xié)議實現(xiàn)的部份。Linux支持TCP/IP,IPX,X.25,AppleTalk等的協(xié)議,各種具體協(xié)議實現(xiàn)的源碼在linux/net/目錄下相應的名稱。在這里主要討論TCP/IP(IPv4)協(xié)議,實現(xiàn)的源碼在linux/net/ipv4,其中l(wèi)inux/net/ipv4/af_inet.c是主要的管理文件。
  網(wǎng)絡接口Socket層為用戶提供的網(wǎng)絡服務的編程接口。主要的源碼在linux/net/socket.c

三.網(wǎng)絡設(shè)備接口部份
    物理層上有許多不同類型的網(wǎng)絡接口設(shè)備, 在文件include/linux/if_arp.h的28行里定義了ARP能處理的各種的物理設(shè)備的標志符。網(wǎng)絡設(shè)備接口要負責具體物理介質(zhì)的控制,從物理介質(zhì)接收以及發(fā)送數(shù)據(jù),并對物理介質(zhì)進行諸如最大數(shù)據(jù)包之類的各種設(shè)置。這里我們以比較簡單的3Com3c501 太網(wǎng)卡的驅(qū)動程序為例,大概講一下這層的工作原理。源碼在Linux/drivers/net/3c501.c。
    我們從直覺上來考慮,一個網(wǎng)卡當然最主要的是完成數(shù)據(jù)的接收和發(fā)送,在這里我們來看看接收和發(fā)送的過程是怎么樣的。
  發(fā)送相對來說比較簡單,在Linux/drivers/net/3c501.c的行475 開始的el_start_xmit()這個函數(shù)就是實際向3Com3c501以太網(wǎng)卡發(fā)送數(shù)據(jù)的函數(shù),具體的發(fā)送工作不外乎是對一些寄存器的讀寫,源碼的注釋很清楚,大家可以看看。
  接收的工作相對來說比較復雜。通常來說,一個新的包到了,或者一個包發(fā)送完成了,都會產(chǎn)生一個中斷。Linux/drivers/net/3c501.c的572開始el_interrupt()的函數(shù)里面,前半部份處理的是包發(fā)送完以后的匯報,后半部份處理的是一個新的包來的,就是說接收到了新的數(shù)據(jù)。el_interrupt()函數(shù)并沒有對新的包進行太多的處理,就交給了接收處理函數(shù)el_receive()。el_receive()首先檢查接收的包是否正確,如果是一個“好”包就會為包分配一個緩沖結(jié)構(gòu)(dev_alloc_skb()),這樣驅(qū)動程序?qū)Π慕邮展ぷ骶屯瓿闪?,通過調(diào)用上層的函數(shù)netif_rx()(net/core/dev.c1214行) ,把包交給上層。

  現(xiàn)在驅(qū)動程序有了發(fā)送和接收數(shù)據(jù)的功能了,驅(qū)動程序怎么樣和上層建立聯(lián)系呢?就是說接收到包以后怎么送給上層,以及上層怎么能調(diào)用驅(qū)動程序的發(fā)送函數(shù)呢?
  由下往上的關(guān)系,是通過驅(qū)動程序調(diào)用上層的netif_rx()(net/core/dev.c 1214行)函數(shù)實現(xiàn)的,驅(qū)動程序通過這個函數(shù)把接到的數(shù)據(jù)交給上層,請注意所有的網(wǎng)卡驅(qū)動程序都需要調(diào)用這個函數(shù)的,這是網(wǎng)絡接口核心層和網(wǎng)絡接口設(shè)備聯(lián)系的橋梁。
  由上往下的關(guān)系就復雜點。網(wǎng)絡接口核心層需要知道有多少網(wǎng)絡設(shè)備可以用,每個設(shè)備的函數(shù)的入口地址等都要知道。網(wǎng)絡接口核心層會大聲喊,“嘿,有多少設(shè)備可以幫我發(fā)送數(shù)據(jù)包?能發(fā)送的請給我排成一隊!”。這一隊就由dev_base開始,指針structnet_device *dev_base (Linux/include/linux/netdevice.h 436行)就是保存了網(wǎng)絡接口核心層所知道的所有設(shè)備。對于網(wǎng)絡接口核心層來說,所有的設(shè)備都是一個net_device結(jié)構(gòu),它在include/linux/netdevice.h,line 233里被定義,這是從網(wǎng)絡接口核心層的角度看到的一個抽象的設(shè)備,我們來看看網(wǎng)絡接口核心層的角度看到的網(wǎng)絡設(shè)備具有的功能:
  struct net_device {
  ………
  open()
  stop()
  hard_start_xmit()
  hard_header()
  rebuild_header()
  set_mac_address()
  do_ioctl()
  set_config()
  hard_header_cache()
  header_cache_update()
  change_mtu()
  tx_timeout()
  hard_header_parse()
  neigh_setup()
  accept_fastpath()
  ………
  }
  如果網(wǎng)絡接口核心層需要由下層發(fā)送數(shù)據(jù)的時候,在dev_base找到設(shè)備以后,就直接調(diào)dev->hard_start_xmit()的這個函數(shù)來讓下層發(fā)數(shù)據(jù)包。
  驅(qū)動程序要讓網(wǎng)絡接口核心層知道自己的存在,當然要加入dev_base所指向的指針鏈,然后把自己的函數(shù)以及各種參數(shù)和net_device里的相應的域?qū)饋?。加入dev_base所指向的指針鏈是通過函數(shù)register_netdev(&dev_3c50)(linux/drivers/net/net_init.c, line 532)
  建立的。而把自己的函數(shù)以和net_device里的相應的域及各種參數(shù)關(guān)系的建立是在el1_probe1()(Linux/drivers/net/3c501.c)里進行的:
  el1_probe1(){
  ………
  dev->open = &el_open;
  dev->hard_start_xmit = &el_start_xmit;
  dev->tx_timeout = &el_timeout;
  dev->watchdog_timeo = HZ;
  dev->stop = &el1_close;
  dev->get_stats = &el1_get_stats;
  dev->set_multicast_list = &set_multicast_list;
  ………
  ether_setup(dev);
  ………
  }
  進一步的對應工作在ether_setup(dev) (drivers/net/net_init.c, line 405 )里進行。我們注意到dev->hard_start_xmit =&el_start_xmit,這樣發(fā)送函數(shù)的關(guān)系就建立了,上層只知道調(diào)用dev->hard_start_xmit這個來發(fā)送數(shù)據(jù),上面的語句就把驅(qū)動程序?qū)嶋H的發(fā)送函數(shù)告訴了上層。

四.網(wǎng)絡接口核心部分
  剛才談論了驅(qū)動程序怎么和網(wǎng)絡接口核心層銜接的。網(wǎng)絡接口核心層知道驅(qū)動程序以及驅(qū)動程序的函數(shù)的入口是通過*dev_base指向的設(shè)備鏈的,而下層是通過調(diào)用這一層的函數(shù)netif_rx()(net/core/dev.c 1214行) 把數(shù)據(jù)傳遞個這一層的。
  網(wǎng)絡接口核心層的上層是具體的網(wǎng)絡協(xié)議,下層是驅(qū)動程序,我們以及解決了下層的關(guān)系,但和上層的關(guān)系沒有解決。先來討論一下網(wǎng)絡接口核心層和網(wǎng)絡協(xié)議族部份的關(guān)系,這種關(guān)系不外乎也是接收和發(fā)送的關(guān)系。
  網(wǎng)絡協(xié)議,例如IP,ARP等的協(xié)議要發(fā)送數(shù)據(jù)包的時候會把數(shù)據(jù)包傳遞給這層,那么這種傳遞是通過什么函數(shù)來發(fā)生的呢?網(wǎng)絡接口核心層通過dev_queue_xmit()(net/core/dev.c,line975)這個函數(shù)向上層提供統(tǒng)一的發(fā)送接口,也就是說無論是IP,還是ARP協(xié)議,通過這個函數(shù)把要發(fā)送的數(shù)據(jù)傳遞給這一層,想發(fā)送數(shù)據(jù)的時候就調(diào)用這個函數(shù)就可以了。dev_queue_xmit()做的工作最后會落實到dev->hard_start_xmit(),而dev->h
ard_start_xmit()會調(diào)用實際的驅(qū)動程序來完成發(fā)送的任務。例如上面的例子中,調(diào)用dev->hard_start_xmit()實際就是調(diào)用了el_start_xmit()。
  現(xiàn)在討論接收的情況。網(wǎng)絡接口核心層通過的函數(shù)netif_rx()(net/core/dev.c 1214行)接收了上層發(fā)送來的數(shù)據(jù),這時候當然要把數(shù)據(jù)包往上層派送。所有的協(xié)議族的下層協(xié)議都需要接收數(shù)據(jù),TCP/IP的IP協(xié)議和ARP協(xié)議,SPX/IPX的IPX協(xié)議,AppleTalk的DDP和AARP協(xié)議等都需要直接從網(wǎng)絡接口核心層接收數(shù)據(jù),網(wǎng)絡接口核心層接收數(shù)據(jù)是如何把包發(fā)給這些協(xié)議的呢?這時的情形和于下層的關(guān)系很相似,網(wǎng)絡接口核心層的下面
可能有許多的網(wǎng)卡的驅(qū)動程序,為了知道怎么向這些驅(qū)動程序發(fā)數(shù)據(jù),前面以及講過時,是通過*dev_base這個指針指向的鏈解決的,現(xiàn)在解決和上層的關(guān)系是通過static struct packet_ptype_base[16]( net/core/dev.c line 164)這個數(shù)組解決的。這個數(shù)組包含了需要接收數(shù)據(jù)包的協(xié)議,以及它們的接收函數(shù)的入口。
  從上面可以看到,IP協(xié)議接收數(shù)據(jù)是通過ip_rcv()函數(shù)的,而ARP協(xié)議是通過arp_rcv()的,網(wǎng)絡接口核心層只要通過這個數(shù)組就可以把數(shù)據(jù)交給上層函數(shù)了。
  如果有協(xié)議想把自己添加到這個數(shù)組,是通過dev_add_pack()(net/core/dev.c, line233)函數(shù),從數(shù)組刪除是通過dev_remove_pack()函數(shù)的。Ip層的注冊是在初始化函數(shù)進行的

void __init ip_init(void) (net/ipv4/ip_output.c, line 1003)
  {
  ………
  dev_add_pack(&ip_packet_type);
  ………
  }
  重新到回我們關(guān)于接收的討論,網(wǎng)絡接口核心層通過的函數(shù)netif_rx()(net/core/dev.c 1214行)接收了上層發(fā)送來的數(shù)據(jù),看看這個函數(shù)做了些什么。
  由于現(xiàn)在還是在中斷的服務里面,所有并不能夠處理太多的東西,剩下的東西就通過cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ)
  交給軟中斷處理, 從open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL)可以知道NET_RX_SOFTIRQ軟中斷的處理函數(shù)是net_rx_action()(net/core/dev.c, line 1419),net_rx_action()根據(jù)數(shù)據(jù)包的協(xié)議類型在數(shù)組ptype_base[16]里找到相應的協(xié)議,并從中知道了接收的處理函數(shù),然后把數(shù)據(jù)包交給處理函數(shù),這樣就交給了上層處理,實際調(diào)用處理函數(shù)是通過net_rx_action()里的pt_prev->func()這一句。例如如果數(shù)據(jù)
包是IP協(xié)議的話,ptype_base[ETH_P_IP]->func()(ip_rcv()),這樣就把數(shù)據(jù)包交給了IP協(xié)議。

五.網(wǎng)絡協(xié)議部分
  協(xié)議層是真正實現(xiàn)是在這一層。在linux/include/linux/socket.h里面,Linux的BSD Socket定義了多至32支持的協(xié)議族,其中PF_INET就是我們最熟悉的TCP/IP協(xié)議族(IPv4, 以下沒有特別聲明都指IPv4)。以這個協(xié)議族為例,看看這層是怎么工作的。實現(xiàn)TCP/IP協(xié)議族的主要文件在inux/net/ipv4/目錄下面,Linux/net/ipv4/af_inet.c為主要的管理文件。
  在Linux2.4.16里面,實現(xiàn)了TCP/IP協(xié)議族里面的的IGMP,TCP,UDP,ICMP,ARP,IP。我們先討論一下這些協(xié)議之間的關(guān)系。IP和ARP協(xié)議是需要直接和網(wǎng)絡設(shè)備接口打交道的協(xié)議,也就是需要從網(wǎng)絡核心模塊(core) 接收數(shù)據(jù)和發(fā)送數(shù)據(jù)的。而其它協(xié)議TCP,UDP,IGMP,ICMP是需要直接利用IP協(xié)議的,需要從IP協(xié)議接收數(shù)據(jù),以及利用IP協(xié)議發(fā)送數(shù)據(jù),同時還要向上層Socket層提供直接的調(diào)用接口??梢钥吹絀P層是一個核心的協(xié)議,向
下需要和下層打交道,又要向上層提供所以的傳輸和接收的服務。
  先來看看IP協(xié)議層。網(wǎng)絡核心模塊(core) 如果接收到IP層的數(shù)據(jù),通過ptype_base[ETH_P_IP] 數(shù)組的IP層的項指向的IP協(xié)議的ip_packet_type->ip_rcv()函數(shù)把數(shù)據(jù)包傳遞給IP層,也就是說IP層通過這個函數(shù)ip_rcv()(linux/net/ipv4/ip_input.c)接收數(shù)據(jù)的。ip_rcv()這個函數(shù)只對IP數(shù)據(jù)保做了一些checksum的檢查工作,如果包是正確的就把包交給了下一個處理函數(shù)ip_rcv_finish()(注意調(diào)用是通過NF_HOOK這個宏實現(xiàn)的)?,F(xiàn)在,ip_rcv_finish()這個函數(shù)真正要完成一些IP層的工作了。IP層要做的主要工作就是路由,要決定把數(shù)據(jù)包往那里送。路由的工作是通過函數(shù)ip_route_input()(/linux/net/ipv4/route.c,line 1622)實現(xiàn)的。對于進來的包可能的路由有這些:
  屬于本地的數(shù)據(jù)(即是需要傳遞給TCP,UDP,IGMP這些上層協(xié)議的) ;
  需要要轉(zhuǎn)發(fā)的數(shù)據(jù)包(網(wǎng)關(guān)或者NAT服務器之類的);
  不可能路由的數(shù)據(jù)包(地址信息有誤);
  我們現(xiàn)在關(guān)心的是如果數(shù)據(jù)是本地數(shù)據(jù)的時候怎么處理。ip_route_input()調(diào)用ip_route_input_slow()(net/ipv4/route.c, line 1312),在ip_route_input_slow()里面的1559行rth->u.dst.input= ip_local_deliver,這就是判斷到IP包是本地的數(shù)據(jù)包,并把本地數(shù)據(jù)包處理函數(shù)的地址返回。好了,路由工作完成了,返回到ip_rcv_finish()。ip_rcv_finish()最后調(diào)用拉skb->dst->input(skb),從上面可以看到,這其實就是調(diào)用了ip_local_deliver()函數(shù),而ip_local_deliver(),接著就調(diào)用了ip_local_deliver_finish()?,F(xiàn)在真正到了往上層傳遞數(shù)據(jù)包的時候了。
  現(xiàn)在的情形和網(wǎng)絡核心模塊層(core) 往上層傳遞數(shù)據(jù)包的情形非常相似,怎么從多個協(xié)議選擇合適的協(xié)議,并且往這個協(xié)議傳遞數(shù)據(jù)呢?網(wǎng)絡網(wǎng)絡核心模塊層(core) 通過一個數(shù)組ptype_base[16]保存了注冊了的所有可以接收數(shù)據(jù)的協(xié)議,同樣網(wǎng)絡協(xié)議層也定義了這樣一個數(shù)組struct net_protocol*inet_protos[MAX_INET_PROTOS](/linux/net/ipv4/protocol.c#L102),它保存了所有需要從IP協(xié)議層接收數(shù)據(jù)的上層協(xié)議(IGMP,TCP,UDP,ICMP)的接收處理函數(shù)的地址。我們來看看TCP協(xié)議的數(shù)據(jù)結(jié)構(gòu)是怎么樣的:
  linux/net/ipv4/protocol.c line67
  static struct inet_protocol tcp_protocol = {
  handler: tcp_v4_rcv,// 接收數(shù)據(jù)的函數(shù)
  err_handler: tcp_v4_err,// 出錯處理的函數(shù)
  next: IPPROTO_PREVIOUS,
  protocol: IPPROTO_TCP,
  name: "TCP"
  };
  第一項就是我們最關(guān)心的了,IP層可以通過這個函數(shù)把數(shù)據(jù)包往TCP層傳的。在linux/net/ipv4/protocol.c的上部,我們可以看到其它協(xié)議層的處理函數(shù)是igmp_rcv(),udp_rcv(), icmp_rcv()。同樣在linux/net/ipv4/protocol.c,往數(shù)組inet_protos[MAX_INET_PROTOS] 里面添加協(xié)議是通過函數(shù)inet_add_protocol()實現(xiàn)的,刪除協(xié)議是通過 inet_del_protocol()實現(xiàn)的。inet_protos[MAX_INET_PROTOS]初始化的過程在linux/net/ipv4/af_inet.c inet_init()初始化函數(shù)里面。
  inet_init(){
  ……
  printk(KERN_INFO "IP Protocols: ");
  for (p = inet_protocol_base; p != NULL;) {
  struct inet_protocol *tmp = (struct inet_protocol *) p->next;
  inet_add_protocol(p);// 添加協(xié)議
  printk("%s%s",p->name,tmp?", ":"n");
  p = tmp;
  ………
  }

Linux最新穩(wěn)定內(nèi)核2.4.x的網(wǎng)絡接口源碼的結(jié)構(gòu)(二)
李元佳

  如果你在Linux啟動的時候有留意啟動的信息, 或者在linux下打命令dmesg就可以看到這一段程序輸出的信息:
  IP Protocols: ICMP,UDP,TCP,IGMP也就是說現(xiàn)在數(shù)組inet_protos[]里面有了ICMP,UDP,TCP,IGMP四個協(xié)議的inet_protocol數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)包含了它們接收數(shù)據(jù)的處理函數(shù)。
  Linux 2.4.16在linux/include/linux/socket.h里定義了32種支持的BSDsocket協(xié)議,常見的有TCP/IP,IPX/SPX,X.25等,而每種協(xié)議還提供不同的服務,例如TCP/IP協(xié)議通過TCP協(xié)議支持連接服務,而通過UDP協(xié)議支持無連接服務,面對這么多的協(xié)議,向用戶提供統(tǒng)一的接口是必要的,這種統(tǒng)一是通過socket來進行的。
  在BSD socket網(wǎng)絡編程的模式下,利用一系列的統(tǒng)一的函數(shù)來利用通信的服務。例如一個典型的利用TCP協(xié)議通信程序是這樣:
  sock_descriptor = socket(AF_INET,SOCK_STREAM,0);
  connect(sock_descriptor, 地址,) ;
  send(sock_descriptor,”hello world”);
  recv(sock_descriptor,buffer,1024,0);
  第一個函數(shù)指定了協(xié)議Inet協(xié)議,即TCP/IP協(xié)議,同時是利用面向連接的服務,這樣就對應到TCP協(xié)議,以后的操作就是利用socket的標準函數(shù)進行的。
  從上面我們可以看到兩個問題,首先socket層需要根據(jù)用戶指定的協(xié)議族(上面是AF_INET) 從下面32種協(xié)議中選擇一種協(xié)議來完成用戶的要求,當協(xié)議族確定以后,還要把特定的服務映射到協(xié)議族下的具體協(xié)議,例如當用戶指定的是面向連接的服務時,Inet協(xié)議族會映射到TCP協(xié)議。
  從多個協(xié)議中選擇用戶指定的協(xié)議,并把具體的出理交給選中的協(xié)議,這和一起網(wǎng)絡核心層向上和向下銜接的問題本質(zhì)上是一樣的,所以解決的方法也是一樣的,同樣還是通過數(shù)組。在Linux/net/socket.c定義了這個數(shù)組staticstruct net_proto_family*net_families[NPROTO] 。數(shù)組的元素已經(jīng)確定了,net_families[2]是TCP/IP協(xié)議,net_families[3]是X.25協(xié)議,具體那一項對應什么協(xié)議,在include/linux/socket.h有定義。但是每一項的數(shù)據(jù)結(jié)構(gòu)net_proto_family的ops是空的,也就是具體協(xié)議處理函數(shù)的地址是不知道的。協(xié)議的處理函數(shù)和ops建立聯(lián)系是通過sock_register()(Linux/net/socket.c)這個函數(shù)建立的,例如TCP/IP協(xié)議的是這樣建立關(guān)系的:
  int __init inet_init(void) (net/ipv4/af_inet.c)
  {
   (void) sock_register(&inet_family_ops);
  }
  只要給出AF_INET(在宏里定義是2),就可以找到net_failies[2] 里面的處理函數(shù)了。
  協(xié)議的映射完成了,現(xiàn)在要進行服務的映射了。上層當然不可能知道下層的什么協(xié)議能對應特定的服務,所以這種映射自然由協(xié)議族自己完成。在TCP/IP協(xié)議族里,這種映射是通過struct list_head inetsw[SOCK_MAX]( net/ipv4/af_inet.c)
  這個數(shù)組進行映射的,在談論這個數(shù)組之前我們來看另外一個數(shù)組inetsw_array[](net/ipv4/af_inet.c)
  static struct inet_protosw inetsw_array[] =
  {
  {
  type: SOCK_STREAM,
  protocol: IPPROTO_TCP,
  prot: &tcp_prot,
  ops: &inet_stream_ops,
  capability: -1,
  no_check: 0,
  flags: INET_PROTOSW_PERMANENT,
  },
  {
  type: SOCK_DGRAM,
  protocol: IPPROTO_UDP,
  prot: &udp_prot,
  ops: &inet_dgram_ops,
  capability: -1,
  no_check: UDP_CSUM_DEFAULT,
  flags: INET_PROTOSW_PERMANENT,
  },
  {
  type: SOCK_RAW,
  protocol: IPPROTO_IP, /* wild card */
  prot: &raw_prot,
  ops: &inet_dgram_ops,
  capability: CAP_NET_RAW,
  no_check: UDP_CSUM_DEFAULT,
  flags: INET_PROTOSW_REUSE,
  }
  };
  我們看到,SOCK_STREAM映射到了TCP協(xié)議,SOCK_DGRAM映射到了UDP協(xié)議,SOCK_RAW映射到了IP協(xié)議?,F(xiàn)在只要把inetsw_array里的三項添加到數(shù)組inetsw[SOCK_MAX]就可以了,添加是通過函數(shù)inet_register_protosw()實現(xiàn)的。在inet_init()(net/ipv4/af_inet.c) 里完成了這些工作。
  還有一個需要映射的就是socket其它諸如accept,send(), connect(),release(),bind()等的操作函數(shù)是怎么映射的呢?我們來看一下上面的數(shù)組的TCP的項
  {
  type: SOCK_STREAM,
  protocol: IPPROTO_TCP,
  prot: &tcp_prot,
  ops: &inet_stream_ops,
  capability: -1,
  no_check: 0,
  flags: INET_PROTOSW_PERMANENT,
  },
  我們看到這種映射是通過ops,和prot來映射的,我們再來看看 tcp_prot這一項:

  struct proto tcp_prot = {
  name: "TCP",
  close: tcp_close,
  connect: tcp_v4_connect,
  disconnect: tcp_disconnect,
  accept: tcp_accept,
  ioctl: tcp_ioctl,
  init: tcp_v4_init_sock,
  destroy: tcp_v4_destroy_sock,
  shutdown: tcp_shutdown,
  setsockopt: tcp_setsockopt,
  getsockopt: tcp_getsockopt,
  sendmsg: tcp_sendmsg,
  recvmsg: tcp_recvmsg,
  backlog_rcv: tcp_v4_do_rcv,
  hash: tcp_v4_hash,
  unhash: tcp_unhash,
  get_port: tcp_v4_get_port,
  };
  所以的映射都已經(jīng)完成了,用戶調(diào)用connect()函數(shù),其實就是調(diào)用了tcp_v4_connect()函數(shù),按照這幅圖,讀起源碼來就簡單了很多了。

六 Socket層
  上一節(jié)把socket層大多數(shù)要討論的東西都談論了,現(xiàn)在只講講socket 層和用戶的銜接。
  系統(tǒng)調(diào)用socket(),bind(),connect(),accept,send(),release()等是在Linux/net/socket.c里面的實現(xiàn)的,系統(tǒng)調(diào)用實現(xiàn)的函數(shù)是相應的函數(shù)名加上sys_的前綴。
  現(xiàn)在看看當用戶調(diào)用socket()這個函數(shù),到底下面發(fā)生了什么。
Socket(AF_INET,SOCK_STREAM,0)調(diào)用了sys_socket(),sys_socket()接著調(diào)用socket_creat(),socket_creat()就要根據(jù)用戶提供的協(xié)議族參數(shù)在net_families[]里尋找合適的協(xié)議族,如果協(xié)議族沒有被安裝就要請求安裝該協(xié)議族的模塊,然后就調(diào)用該協(xié)議族的create()函數(shù)的處理句柄。根據(jù)參數(shù)AF_INET,inet_creat()就被調(diào)用了,在inet_creat()根據(jù)服務類型在inetsw[SOCK_MAX]選擇合適的協(xié)議,并把協(xié)議的操作集賦給socket就是了,根據(jù)SOCK_STREAM,TCP協(xié)議被選中,
  inet_creat(){
  answer=inetsw [用戶要求服務服務] ;
  sock->ops = answer->ops;
  sk->prot = answer->prot
  }
  到此為止,上下都打通了,該是大家讀源碼的時候了

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
TCP/IP學習(28)
深入分析原始套接口
TCP/IP協(xié)議棧在Linux內(nèi)核中的運行時序分析
《ARM9嵌入式系統(tǒng)設(shè)計基礎(chǔ)教程》第7章嵌入式系統(tǒng)網(wǎng)絡接口
基于Linux操作系統(tǒng)下的TCP/IP網(wǎng)絡通信研究與應用
套接字選項(四)_深度探索Linux內(nèi)核
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服