99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

linux TCP/IP 協(xié)議棧源碼分析

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-09 15:04 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一.linux內(nèi)核網(wǎng)絡(luò)棧代碼的準(zhǔn)備知識(shí)

  1. linux內(nèi)核ipv4網(wǎng)絡(luò)部分分層結(jié)構(gòu):

BSD socket層: 這一部分處理BSD socket相關(guān)操作,每個(gè)socket在內(nèi)核中以struct socket結(jié)構(gòu)體現(xiàn)。這一部分的文件

主要有:/net/socket.c /net/protocols.c etc INET socket層:BSD socket是個(gè)可以用于各種網(wǎng)絡(luò)協(xié)議的接口,而當(dāng)用于tcp/ip,即建立了AF_INET形式的socket時(shí),

還需要保留些額外的參數(shù),于是就有了struct sock結(jié)構(gòu)。文件主要

有:/net/ipv4/protocol.c /net/ipv4/af_inet.c /net/core/sock.c etc TCP/UDP層:處理傳輸層的操作,傳輸層用struct inet_protocol和struct proto兩個(gè)結(jié)構(gòu)表示。文件主要

有:/net/ipv4/udp.c /net/ipv4/datagram.c /net/ipv4/tcp.c /net/ipv4/tcp_input.c /net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks.c /net/ipv4/tcp_output.c /net/ipv4/tcp_timer.c

etc IP層:處理網(wǎng)絡(luò)層的操作,網(wǎng)絡(luò)層用struct packet_type結(jié)構(gòu)表示。文件主要有:/net/ipv4/ip_forward.c

ip_fragment.c ip_input.c ip_output.c etc. 數(shù)據(jù)鏈路層和驅(qū)動(dòng)程序:每個(gè)網(wǎng)絡(luò)設(shè)備以struct net_device表示,通用的處理在dev.c中,驅(qū)動(dòng)程序都在/driver/net目

錄下。

  1. 兩臺(tái)主機(jī)建立udp通信所走過的函數(shù)列表

^
| sys_read fs/read_write.c
| sock_read net/socket.c
| sock_recvmsg net/socket.c
| inet_recvmsg net/ipv4/af_inet.c
| udp_recvmsg net/ipv4/udp.c

skb_recv_datagram net/core/datagram.c
sock_queue_rcv_skb include/net/sock.h
udp_queue_rcv_skb net/ipv4/udp.c
udp_rcv net/ipv4/udp.c
ip_local_deliver_finish net/ipv4/ip_input.c
ip_local_deliver net/ipv4/ip_input.c
ip_recv net/ipv4/ip_input.c
net_rx_action net/dev.c
-------------------------------------------
netif_rx net/dev.c
el3_rx driver/net/3c309.c
el3_interrupt driver/net/3c309.c
==========================
sys_write fs/read_write.c
sock_writev net/socket.c
sock_sendmsg net/socket.c
inet_sendmsg net/ipv4/af_inet.c
udp_sendmsg net/ipv4/udp.c
ip_build_xmit net/ipv4/ip_output.c
output_maybe_reroute net/ipv4/ip_output.c
ip_output net/ipv4/ip_output.c
ip_finish_output net/ipv4/ip_output.c
dev_queue_xmit net/dev.c
--------------------------------------------
el3_start_xmit driver/net/3c309.c
V

二.linux的tcp-ip棧代碼的詳細(xì)分析

1.數(shù)據(jù)結(jié)構(gòu)(msghdr,sk_buff,socket,sock,proto_ops,proto)

bsd套接字層,操作的對(duì)象是socket,數(shù)據(jù)存放在msghdr這樣的數(shù)據(jù)結(jié)構(gòu):

創(chuàng)建socket需要傳遞family,type,protocol三個(gè)參數(shù),創(chuàng)建socket其實(shí)就是創(chuàng)建一個(gè)socket實(shí)例,然后創(chuàng)建一個(gè)文件描述符結(jié)構(gòu),并且互相建立一些關(guān)聯(lián),即建立互相連接的指針,并且初始化這些對(duì)文件的寫讀操作映射到socket的read,write函數(shù)上來。

同時(shí)初始化socket的操作函數(shù)(proto_ops結(jié)構(gòu)),如果傳入的type參數(shù)是STREAM類型,那么就初始化為SOCKET->ops為inet_stream_ops,如果是DGRAM類型,則SOCKET-ops為inet_dgram_ops。對(duì)于inet_stream_ops其實(shí)是一個(gè)結(jié)構(gòu)體,包含了stream類型的socket操作的一些入口函數(shù),在這些函數(shù)里主要做的是對(duì)socket進(jìn)行相關(guān)的操作,同時(shí)通過調(diào)用下面提到的sock中的相關(guān)操作完成socket到sock層的傳遞。比如在inet_stream_ops里有個(gè)inet_release的操作,這個(gè)操作除了釋放socket的類型空間操作外,還通過調(diào)用socket連接的sock的close操作,對(duì)于stream類型來說,即tcp_close來關(guān)閉sock

釋放sock。

創(chuàng)建socket同時(shí)還創(chuàng)建sock數(shù)據(jù)空間,初始化sock,初始化過程主要做的事情是初始化三個(gè)隊(duì)列,receive_queue(接收到的數(shù)據(jù)包sk_buff鏈表隊(duì)列),send_queue(需要發(fā)送數(shù)據(jù)包的sk_buff鏈表隊(duì)列),backlog_queue(主要用于tcp中三次握手成功的那些數(shù)據(jù)包,自己猜的),根據(jù)family、type參數(shù),初始化sock的操作,比如對(duì)于family為inet類型的,type為stream類型的,sock->proto初始化為tcp_prot.其中包括stream類型的協(xié)議sock操作對(duì)應(yīng)的入口函數(shù)。

在一端對(duì)socket進(jìn)行write的過程中,首先會(huì)把要write的字符串緩沖區(qū)整理成msghdr的數(shù)據(jù)結(jié)構(gòu)形式(參見linux內(nèi)核2.4版源代碼分析大全),然后調(diào)用sock_sendmsg把msghdr的數(shù)據(jù)傳送至inet層,對(duì)于msghdr結(jié)構(gòu)中數(shù)據(jù)區(qū)中的每個(gè)數(shù)據(jù)包,創(chuàng)建sk_buff結(jié)構(gòu),填充數(shù)據(jù),掛至發(fā)送隊(duì)列。一層層往下層協(xié)議傳遞。一下每層協(xié)議不再對(duì)數(shù)據(jù)進(jìn)行拷貝。而是對(duì)sk_buff結(jié)構(gòu)進(jìn)行操作。

inet套接字及以下層 數(shù)據(jù)存放在sk_buff這樣的數(shù)據(jù)結(jié)構(gòu)里:

路由:

在linux的路由系統(tǒng)主要保存了三種與路由相關(guān)的數(shù)據(jù),第一種是在物理上和本機(jī)相連接的主機(jī)地址信息表,第二種是保存了在網(wǎng)絡(luò)訪問中判斷一個(gè)網(wǎng)絡(luò)地址應(yīng)該走什么路由的數(shù)據(jù)表;第三種是最新使用過的查詢路由地址的緩存地址數(shù)據(jù)表。

1.neighbour結(jié)構(gòu) neighbour_table{ }是一個(gè)包含和本機(jī)所連接的所有鄰元素的信息的數(shù)據(jù)結(jié)構(gòu)。該結(jié)構(gòu)中有個(gè)元素是neighbour結(jié)構(gòu)的數(shù)組,數(shù)組的每一個(gè)元素都是一個(gè)對(duì)應(yīng)于鄰機(jī)的neighbour結(jié)構(gòu),系統(tǒng)中由于協(xié)議的不同,會(huì)有不同的判斷鄰居的方式,每種都有neighbour_table{}類型的實(shí)例,這些實(shí)例是通過neighbour_table{}中的指針next串聯(lián)起來的。在neighbour結(jié)構(gòu)中,包含有與該鄰居相連的網(wǎng)絡(luò)接口設(shè)備net_device的指針,網(wǎng)絡(luò)接口的硬件地址,鄰居的硬件地址,包含有neigh_ops{}指針,這些函數(shù)指針是直接用來連接傳輸數(shù)據(jù)的,包含有queue_xmit(struct * sk_buff)函數(shù)入口地址,這個(gè)函數(shù)可能會(huì)調(diào)用硬件驅(qū)動(dòng)程序的發(fā)送函數(shù)。

2.FIB結(jié)構(gòu) 在FIB中保存的是最重要的路由規(guī)則,通過對(duì)FIB數(shù)據(jù)的查找和換算,一定能夠獲得路由一個(gè)地址的方法。系統(tǒng)中路由一般采取的手段是:先到路由緩存中查找表項(xiàng),如果能夠找到,直接對(duì)應(yīng)的一項(xiàng)作為路由的規(guī)則;如果不能找到,那么就到FIB中根據(jù)規(guī)則換算傳算出來,并且增加一項(xiàng)新的,在路由緩存中將項(xiàng)目添加進(jìn)去。

3.route結(jié)構(gòu)(即路由緩存中的結(jié)構(gòu))

數(shù)據(jù)鏈路層:

net_device{}結(jié)構(gòu),對(duì)應(yīng)于每一個(gè)網(wǎng)絡(luò)接口設(shè)備。這個(gè)結(jié)構(gòu)中包含很多可以直接獲取網(wǎng)卡信息的函數(shù)和變量,同時(shí)包含很多對(duì)于網(wǎng)卡操作的函數(shù),這些直接指向該網(wǎng)卡驅(qū)動(dòng)程序的許多函數(shù)入口,包括發(fā)送接收數(shù)據(jù)幀到緩沖區(qū)等。當(dāng)這些完成后,比如數(shù)據(jù)接收到緩沖區(qū)后便由netif_rx(在net/core/dev.c各種設(shè)備驅(qū)動(dòng)程序的上層框架程序)把它們組成sk_buff形式掛到系統(tǒng)接收的backlog隊(duì)列然后交由上層網(wǎng)絡(luò)協(xié)議處理。同樣,對(duì)于上層協(xié)議處理下來的那些sk_buff。便由dev_queue_xmit函數(shù)放入網(wǎng)絡(luò)緩沖區(qū),交給網(wǎng)卡驅(qū)動(dòng)程序的發(fā)送程序處理。

在系統(tǒng)中存在一張鏈表dev_base將系統(tǒng)中所有的net_device{}結(jié)構(gòu)連在一起。對(duì)應(yīng)于內(nèi)核初始化而言,系統(tǒng)啟動(dòng)時(shí)便為每個(gè)所有可能支持的網(wǎng)絡(luò)接口設(shè)備申請(qǐng)了一個(gè)net_device{}空間并串連起來,然后對(duì)每個(gè)接點(diǎn)運(yùn)行檢測過程,如果檢測成功,則在dev_base鏈表中保留這個(gè)接點(diǎn),否則刪除。對(duì)應(yīng)于模塊加載來說,則是調(diào)用register_netdev()注冊(cè)net_device,在這個(gè)函數(shù)中運(yùn)行檢測過程,如果成功,則加到dev_base鏈表。否則就返回檢測不到信息。刪除同理,調(diào)用

unregister_netdev。

2.啟動(dòng)分析

2.1 初始化進(jìn)程 :start-kernel(main.c)---->do_basic_setup(main.c)---->sock_init(/net/socket.c)---->do_initcalls(main.c)

void __init sock_init(void)
{
int i;
printk(KERN_INFO "Linux NET4.0 for Linux 2.4/n");
printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039/n");
/*
* Initialize all address (protocol) families. 每一項(xiàng)表示的是針對(duì)一個(gè)地址族的操作集合,例如對(duì)于ipv4來說,在net/ipv4/af_inet.c文件中的函數(shù)inet_proto_init()就調(diào)用sock_register()函數(shù)將inet_families_ops初始化到屬于IPV4的net_families數(shù)組中的一項(xiàng)。
*/
for (i = 0; i < NPROTO; i++)
net_families[i] = NULL;
/*
* Initialize sock SLAB cache.初始化對(duì)于sock結(jié)構(gòu)預(yù)留的內(nèi)存的slab緩存。
*/
sk_init();
#ifdef SLAB_SKB
/*
* Initialize skbuff SLAB cache 初始化對(duì)于skbuff結(jié)構(gòu)的slab緩存。以后對(duì)于skbuff的申請(qǐng)可以通過函數(shù)kmem_cache_alloc()在這個(gè)緩存中申請(qǐng)空間。
*/
skb_init();
#endif
/*
* Wan router layer.
*/
#ifdef CONFIG_WAN_ROUTER
wanrouter_init();
#endif
/*
* Initialize the protocols module. 向系統(tǒng)登記sock文件系統(tǒng),并且將其安裝到系統(tǒng)上來。
*/
register_filesystem(&sock_fs_type);
sock_mnt = kern_mount(&sock_fs_type);
/* The real protocol initialization is performed when
* do_initcalls is run.
*/
/*
* The netlink device handler may be needed early.
*/
#ifdef CONFIG_NET
rtnetlink_init();
#endif
#ifdef CONFIG_NETLINK_DEV
init_netlink();
#endif
#ifdef CONFIG_NETFILTER
netfilter_init();
#endif
#ifdef CONFIG_BLUEZ
bluez_init();
#endif
/*yfhuang ipsec*/
#ifdef CONFIG_IPSEC
pfkey_init();
#endif
/*yfhuang ipsec*/
}

2.2 do_initcalls() 中做了其它的初始化,其中包括

協(xié)議初始化,路由初始化,網(wǎng)絡(luò)接口設(shè)備初始化

(例如inet_init函數(shù)以_init開頭表示是系統(tǒng)初始化時(shí)做,函數(shù)結(jié)束后跟module_init(inet_init),這是一個(gè)宏,在include/linux/init.c中定義,展開為_initcall(inet_init),表示這個(gè)函數(shù)在do_initcalls被調(diào)用了)

2.3 協(xié)議初始化

此處主要列舉inet協(xié)議的初始化過程。

static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
struct inet_protosw *q;
struct list_head *r;
printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0/n");
if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
printk(KERN_CRIT "inet_proto_init: panic/n");
return -EINVAL;
}
/*
* Tell SOCKET that we are alive... 注冊(cè)socket,告訴socket inet類型的地址族已經(jīng)準(zhǔn)備好了
*/
(void) sock_register(&inet_family_ops);
/*
* Add all the protocols. 包括arp,ip、ICMP、UPD、tcp_v4、tcp、igmp的初始化,主要初始化各種協(xié)議對(duì)應(yīng)的inode和socket變量。
其中arp_init完成系統(tǒng)中路由部分neighbour表的初始化
ip_init完成ip協(xié)議的初始化。在這兩個(gè)函數(shù)中,都通過定義一個(gè)packet_type結(jié)構(gòu)的變量將這種數(shù)據(jù)包對(duì)應(yīng)的協(xié)議發(fā)送數(shù)據(jù)、允許發(fā)送設(shè)備都做初始化。
*/
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);
printk("%s%s",p->name,tmp?", ":"/n");
p = tmp;
}
/* Register the socket-side information for inet_create. */
for(r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
INIT_LIST_HEAD(r);
for(q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
inet_register_protosw(q);
/*
* Set the ARP module up
*/
arp_init();
/*
* Set the IP module up
*/
ip_init();
tcp_v4_init(&inet_family_ops);
/* Setup TCP slab cache for open requests. */
tcp_init();
/*
* Set the ICMP layer up
*/
icmp_init(&inet_family_ops);
/* I wish inet_add_protocol had no constructor hook...
I had to move IPIP from net/ipv4/protocol.c :-( --ANK
*/
#ifdef CONFIG_NET_IPIP
ipip_init();
#endif
#ifdef CONFIG_NET_IPGRE
ipgre_init();
#endif
/*
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
/*
* Create all the /proc entries.
*/
#ifdef CONFIG_PROC_FS
proc_net_create ("raw", 0, raw_get_info);
proc_net_create ("netstat", 0, netstat_get_info);
proc_net_create ("snmp", 0, snmp_get_info);
proc_net_create ("sockstat", 0, afinet_get_info);
proc_net_create ("tcp", 0, tcp_get_info);
proc_net_create ("udp", 0, udp_get_info);
#endif /* CONFIG_PROC_FS */
ipfrag_init();
return 0;
}
module_init(inet_init);

2.4 路由初始化(包括neighbour表、FIB表、和路由緩存表的初始化工作)

2.4.1 rtcache表 ip_rt_init()函數(shù) 在net/ipv4/ip_output中調(diào)用,net/ipv4/route.c中定義

2.4.2 FIB初始化 在ip_rt_init()中調(diào)用 在net/ipv4/fib_front.c中定義

2.4.3 neigbour表初始化 arp_init()函數(shù)中定義

2.5 網(wǎng)絡(luò)接口設(shè)備初始化

在系統(tǒng)中網(wǎng)絡(luò)接口都是由一個(gè)dev_base鏈表進(jìn)行管理的。通過內(nèi)核的啟動(dòng)方式也是通過這個(gè)鏈表進(jìn)行操作的。在系統(tǒng)啟動(dòng)之初,將所有內(nèi)核能夠支持的網(wǎng)絡(luò)接口都初始化成這個(gè)鏈表中的一個(gè)節(jié)點(diǎn),并且每個(gè)節(jié)點(diǎn)都需要初始化出init函數(shù)指針,用來檢測網(wǎng)絡(luò)接口設(shè)備。然后,系統(tǒng)遍歷整個(gè)dev_base鏈表,對(duì)每個(gè)節(jié)點(diǎn)分別調(diào)用init函數(shù)指針,如果成功,證明網(wǎng)絡(luò)接口設(shè)備可用,那么這個(gè)節(jié)點(diǎn)就可以進(jìn)一步初始化,如果返回失敗,那么證明該網(wǎng)絡(luò)設(shè)備不存在或是不可用,只能將該節(jié)點(diǎn)刪除。啟動(dòng)結(jié)束之后,在dev_base中剩下的都是可以用的網(wǎng)絡(luò)接口設(shè)備。

2.5.1 do_initcalls---->net_dev_init()(net/core/dev.c)------>ethif_probe()(drivers/net/Space.c,在netdevice{}結(jié)構(gòu)的init中調(diào)用,這邊ethif_probe是以太網(wǎng)卡針對(duì)的調(diào)用)

3.網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序(略)

4.網(wǎng)絡(luò)連接

4.1 連接的建立和關(guān)閉

tcp連接建立的代碼如下:

server=gethostbyname(SERVER_NAME);
sockfd=socket(AF_INET,SOCK_STREAM,0);
address.sin_family=AF_INET;
address.sin_port=htons(PORT_NUM);
memcpy(&address.sin_addr,server->h_addr,server->h_length);
connect(sockfd,&address,sizeof(address));

連接的初始化與建立期間主要發(fā)生的事情如下:

1)sys_socket調(diào)用:調(diào)用socket_creat(),創(chuàng)建出一個(gè)滿足傳入?yún)?shù)family、type、和protocol的socket,調(diào)用sock_map_fd()獲取一個(gè)未被使用的文件描述符,并且申請(qǐng)并初始化對(duì)應(yīng)的file{}結(jié)構(gòu)。

2)sock_creat():創(chuàng)建socket結(jié)構(gòu),針對(duì)每種不同的family的socket結(jié)構(gòu)的初始化,就需要調(diào)用不同的create函數(shù)來完成。對(duì)應(yīng)于inet類型的地址來說,在網(wǎng)絡(luò)協(xié)議初始化時(shí)調(diào)用sock_register()函數(shù)中完成注冊(cè)的定義如下:

struct net_proto_family inet_family_ops={
PF_INET;
inet_create
};

所以inet協(xié)議最后會(huì)調(diào)用inet_create函數(shù)。

3)inet_create: 初始化sock的狀態(tài)設(shè)置為SS_UNCONNECTED,申請(qǐng)一個(gè)新的sock結(jié)構(gòu),并且初始化socket的成員ops初始化為inet_stream_ops,而sock的成員prot初始化為tcp_prot。然后調(diào)用sock_init_data,將該socket結(jié)構(gòu)的變量sock和sock類型的變量關(guān)聯(lián)起來。

4)在系統(tǒng)初始化完畢后便是進(jìn)行connect的工作,系統(tǒng)調(diào)用connect將一個(gè)和socket結(jié)構(gòu)關(guān)聯(lián)的文件描述符和一個(gè)sockaddr{}結(jié)構(gòu)的地址對(duì)應(yīng)的遠(yuǎn)程機(jī)器相關(guān)聯(lián),并且調(diào)用各個(gè)協(xié)議自己對(duì)應(yīng)的connect連接函數(shù)。對(duì)應(yīng)于tcp類型,則sock->ops->connect便為inet_stream_connect。

5)inet_stream_connect: 得到sk,sk=sock->sk,鎖定sk,對(duì)自動(dòng)獲取sk的端口號(hào)存放在sk->num中,并且用htons()函數(shù)轉(zhuǎn)換存放在sk->sport中。然后調(diào)用sk->prot->connect()函數(shù)指針,對(duì)tcp協(xié)議來說就是tcp_v4_connect()函數(shù)。然后將sock->state狀態(tài)字設(shè)置為SS_CONNECTING,等待后面一系列的處理完成之后,就將狀態(tài)改成SS_CONNECTTED。

  1. tcp_v4_connect():調(diào)用函數(shù)ip_route_connect(),尋找合適的路由存放在rt中。ip_route_connect找兩次,第一次找到下一跳的ip地址,在路由緩存或fib中找到,然后第二次找到下一跳的具體鄰居,到neigh_table中找到。然后申請(qǐng)出tcp頭的空間存放在buff中。將sk中相關(guān)地址數(shù)據(jù)做一些針對(duì)路由的變動(dòng),并且初始化一個(gè)tcp連接的序列號(hào),調(diào)用函數(shù)tcp_connect(),初始化tcp頭,并設(shè)置tcp處理需要的定時(shí)器。一次connect()建立的過程就結(jié)束了。

連接的關(guān)閉主要如下:

1)close: 一個(gè)socket文件描述符對(duì)應(yīng)的file{}結(jié)構(gòu)中,有一個(gè)file_operations{}結(jié)構(gòu)的成員f_ops,它的初始化關(guān)閉函數(shù)為sock_close函數(shù)。

2)sock_close:調(diào)用函數(shù)sock_release(),參數(shù)為一個(gè)socket{}結(jié)構(gòu)的指針。

3)sock_release:調(diào)用inet_release,并釋放socket的指針和文件空間

4)inet_release: 調(diào)用和該socket對(duì)應(yīng)協(xié)議的關(guān)閉函數(shù)inet_release,如果是tcp協(xié)議,那么調(diào)用的是tcp_close;最后釋放sk。

4.2 數(shù)據(jù)發(fā)送流程圖

各層主要函數(shù)以及位置功能說明:

1)sock_write:初始化msghdr{}結(jié)構(gòu) net/socket.c

2)sock_sendmsg:net/socket.c

3)inet_sendmsg:net/ipv4/af_net.c

4)tcp_sendmsg:申請(qǐng)sk_buff{}結(jié)構(gòu)的空間,把msghdr{}結(jié)構(gòu)中的數(shù)據(jù)填入sk_buff空間。net/ipv4/tcp.c

5)tcp_send_skb:net/ipv4/tcp_output.c

6)tcp_transmit_skb:net/ipv4/tcp_output.c

7)ip_queue_xmit:net/ipv4/ip_output.c

8)ip_queue_xmit2:net/ipv4/ip_output.c

9)ip_output:net/ipv4/ip_output.c

10)ip_finish_output:net/ipv4/ip_output.c

11)ip_finish_output2:net/ipv4/ip_output.c

12)neigh_resolve_output:net/core/neighbour.c

13)dev_queue_xmit:net/core/dev.c

4.3 數(shù)據(jù)接收流程圖

各層主要函數(shù)以及位置功能說明:

1)sock_read:初始化msghdr{}的結(jié)構(gòu)類型變量msg,并且將需要接收的數(shù)據(jù)存放的地址傳給msg.msg_iov->iov_base. net/socket.c

2)sock_recvmsg: 調(diào)用函數(shù)指針sock->ops->recvmsg()完成在INET Socket層的數(shù)據(jù)接收過程.其中sock->ops被初始化為inet_stream_ops,其成員recvmsg對(duì)應(yīng)的函數(shù)實(shí)現(xiàn)為inet_recvmsg()函數(shù). net/socket.c

3)sys_recv()/sys_recvfrom():分別對(duì)應(yīng)著面向連接和面向無連接的協(xié)議兩種情況. net/socket.c

4)inet_recvmsg:調(diào)用sk->prot->recvmsg函數(shù)完成數(shù)據(jù)接收,這個(gè)函數(shù)對(duì)于tcp協(xié)議便是tcp_recvmsg net/ipv4/af_net.c

5)tcp_recvmsg:從網(wǎng)絡(luò)協(xié)議棧接收數(shù)據(jù)的動(dòng)作,自上而下的觸發(fā)動(dòng)作一直到這個(gè)函數(shù)為止,出現(xiàn)了一次等待的過程.函數(shù)tcp_recvmsg可能會(huì)被動(dòng)地等待在sk的接收數(shù)據(jù)隊(duì)列上,也就是說,系統(tǒng)中肯定有其他地方會(huì)去修改這個(gè)隊(duì)列使得tcp_recvmsg可以進(jìn)行下去.入口參數(shù)sk是這個(gè)網(wǎng)絡(luò)連接對(duì)應(yīng)的sock{}指針,msg用于存放接收到的數(shù)據(jù).接收數(shù)據(jù)的時(shí)候會(huì)去遍歷接收隊(duì)列中的數(shù)據(jù),找到序列號(hào)合適的.

但讀取隊(duì)列為空時(shí)tcp_recvmsg就會(huì)調(diào)用tcp_v4_do_rcv使用backlog隊(duì)列填充接收隊(duì)列.

6)tcp_v4_rcv:tcp_v4_rcv被ip_local_deliver函數(shù)調(diào)用,是從IP層協(xié)議向INET Socket層提交的"數(shù)據(jù)到"請(qǐng)求,入口參數(shù)skb存放接收到的數(shù)據(jù),len是接收的數(shù)據(jù)的長度,這個(gè)函數(shù)首先移動(dòng)skb->data指針,讓它指向tcp頭,然后更新tcp層的一些數(shù)據(jù)統(tǒng)計(jì),然后進(jìn)行tcp的一些值的校驗(yàn).再從INET Socket層中已經(jīng)建立的sock{}結(jié)構(gòu)變量中查找正在等待當(dāng)前到達(dá)數(shù)據(jù)的哪一項(xiàng).可能這個(gè)sock{}結(jié)構(gòu)已經(jīng)建立,或者還處于監(jiān)聽端口、等待數(shù)據(jù)連接的狀態(tài)。返回的sock結(jié)構(gòu)指針存放在sk中。然后根據(jù)其他進(jìn)程對(duì)sk的操作情況,將skb發(fā)送到合適的位置.調(diào)用如下:

TCP包接收器(tcp_v4_rcv)將TCP包投遞到目的套接字進(jìn)行接收處理. 當(dāng)套接字正被用戶鎖定,TCP包將暫時(shí)排入該套接字的后備隊(duì)列(sk_add_backlog).這時(shí)如果某一用戶線程企圖鎖定該套接字(lock_sock),該線程被排入套接字的后備處理等待隊(duì)列(sk->lock.wq).當(dāng)用戶釋放上鎖的套接字時(shí)(release_sock,在tcp_recvmsg中調(diào)用),后備隊(duì)列中的TCP包被立即注入TCP包處理器(tcp_v4_do_rcv)進(jìn)行處理,然后喚醒等待隊(duì)列中最先的一個(gè)用戶來獲得其鎖定權(quán). 如果套接字未被上鎖,當(dāng)用戶正在讀取該套接字時(shí), TCP包將被排入套接字的預(yù)備隊(duì)列(tcp_prequeue),將其傳遞到該用戶線程上下文中進(jìn)行處理.如果添加到sk->prequeue不成功,便可以添加到 sk->receive_queue隊(duì)列中(用戶線程可以登記到預(yù)備隊(duì)列,當(dāng)預(yù)備隊(duì)列中出現(xiàn)第一個(gè)包時(shí)就喚醒等待線程.) /net/tcp_ipv4.c

7)ip_rcv、ip_rcv_finish:從以太網(wǎng)接收數(shù)據(jù),放到skb里,作ip層的一些數(shù)據(jù)及選項(xiàng)檢查,調(diào)用ip_route_input()做路由處理,判斷是進(jìn)行ip轉(zhuǎn)發(fā)還是將數(shù)據(jù)傳遞到高一層的協(xié)議.調(diào)用skb->dst->input函數(shù)指針,這個(gè)指針的實(shí)現(xiàn)可能有多種情況,如果路由得到的結(jié)果說明這個(gè)數(shù)據(jù)包應(yīng)該轉(zhuǎn)發(fā)到其他主機(jī),這里的input便是ip_forward;如果數(shù)據(jù)包是給本機(jī)的,那么input指針初始化為ip_local_deliver函數(shù)./net/ipv4/ip_input.c

8)ip_local_deliver、ip_local_deliver_finish:入口參數(shù)skb存放需要傳送到上層協(xié)議的數(shù)據(jù),從ip頭中獲取是否已經(jīng)分拆的信息,如果已經(jīng)分拆,則調(diào)用函數(shù)ip_defrag將數(shù)據(jù)包重組。然后通過調(diào)用ip_prot->handler指針調(diào)用tcp_v4_rcv(tcp)。ip_prot是inet_protocol結(jié)構(gòu)指針,是用來ip層登記協(xié)議的,比如由udp,tcp,icmp等協(xié)議。 /net/ipv4/ip_input.c

Linux通過同時(shí)對(duì)多種通信協(xié)議的支持來提供通用的底層基礎(chǔ)服務(wù)。它的第一個(gè)網(wǎng)絡(luò)模型的版本是4.3 BSD,也稱為Net/1,今天的Linux已經(jīng)使用Net/4 (Linux 2.2),其中大多數(shù)代碼已經(jīng)完全和BSD的版本不同,但是它依然支持UINX平臺(tái)之間程序的移植。

Linux網(wǎng)絡(luò)套接字實(shí)現(xiàn)的模式是UNIX下的普遍標(biāo)準(zhǔn)。同時(shí),Net/4的網(wǎng)絡(luò)層是完全另起爐灶重寫的。首先,新的網(wǎng)絡(luò)層盡可能地實(shí)行并行處理, 因此其伸縮性比起以前的版本,不可同日而語。其次,它包括了許多的優(yōu)化,以便繞過不少流行操作系統(tǒng)網(wǎng)絡(luò)實(shí)現(xiàn)中的不合理處(例如Windows)。到目前為止,Linux 是唯一與IPv4和IPv6協(xié)議標(biāo)準(zhǔn)完全保持兼容的操作系統(tǒng),而Linux2.4的IPv4伸縮性又大有提高。

Linux支持的六種不同通信協(xié)議族:

1) TCP/IP (使用TCP/IP的Internet 協(xié)議族),本文討論的重點(diǎn)。

2) UNIX域協(xié)議 (一種進(jìn)程間通信的協(xié)議)

3) X25協(xié)議

4) AX25協(xié)議 (業(yè)余無線X25)

5)IPX協(xié)議 (Novell IPX)

6) APPLETALK協(xié)議 (AppleTalk DDP)

1.1 內(nèi)核源代碼的組織

表1是本文要使用的Linux Net/4網(wǎng)絡(luò)源代碼的,其中大部分位于目錄/usr/src/linux-2.2.x/net,列表如下,

插口層
BSD Socket
/net/socket.c
/net/protocols.c
INET Socket
/ipv4/protocol.c
/ipv4/af_inet.c
/net/ipv4/core/sock.c
協(xié)議層
TCP/UDP
/net/ipv4/udp.c
/net/ipv4/datagram.c
/net/ipv4/tcp_input.c
/net/ipv4//tcp_output.c
/net/ipv4/tcp.c
/net/ipv4/tcp_minisocks.c
/net/ipv4/tcp_timer.c etc...
IP
/net/ipv4/ip_forward.c
/net/ipv4/ip_fragment.c
/net/ipv4/ip_input.c
/net/ipv4/ip_output.c
接口層
Ethernet
......

1.2 Linux中TCP/IP網(wǎng)絡(luò)層次結(jié)構(gòu)與實(shí)現(xiàn) Linux通過一組相鄰的軟件層實(shí)現(xiàn)了TCP/IP模型,它由BSD Socket層、INET

Socket層、傳輸層、網(wǎng)絡(luò)層,和鏈路層構(gòu)成。應(yīng)用程序使用系統(tǒng)調(diào)用向內(nèi)核函數(shù)傳遞參數(shù)和數(shù)據(jù)從而進(jìn)入內(nèi)核空間,由內(nèi)核中注冊(cè)的內(nèi)核函數(shù)對(duì)相應(yīng)的數(shù)據(jù)結(jié)構(gòu)進(jìn)行處理。Linux的TCP/IP層次結(jié)構(gòu)和實(shí)現(xiàn)方式如圖所示。

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11511

    瀏覽量

    213765
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1402

    瀏覽量

    81038
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    671

    瀏覽量

    30328
  • 協(xié)議棧
    +關(guān)注

    關(guān)注

    2

    文章

    145

    瀏覽量

    34104
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    全硬件TCP/IP協(xié)議學(xué)習(xí)筆記(第四天:全硬件TCP/IP協(xié)議模塊學(xué)習(xí))

    /IP協(xié)議的不同歸類為兩大類,第一類是傳統(tǒng)的軟件TCP/IP協(xié)議
    的頭像 發(fā)表于 12-18 10:27 ?9159次閱讀
    全硬件<b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>學(xué)習(xí)筆記(第四天:全硬件<b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b><b class='flag-5'>協(xié)議</b>模塊學(xué)習(xí))

    如何去簡化Simplified TCP/IP協(xié)議?

    Simplified TCP/IP協(xié)議的特點(diǎn)是什么?如何去簡化Simplified TCP/IP
    發(fā)表于 05-26 07:23

    TCP/IP協(xié)議有何功能

    TCP/IP協(xié)議是什么?TCP/IP協(xié)議
    發(fā)表于 10-14 06:39

    UCOS下的TCP-IP-PPP協(xié)議

    UCOS下的TCP-IP-PPP協(xié)議
    發(fā)表于 03-25 16:51 ?61次下載

    51+單片機(jī)TCP-IP+協(xié)議ZLIP源碼

    單片機(jī)上網(wǎng)技術(shù),是當(dāng)前的一個(gè)熱門技術(shù)。單片機(jī)上網(wǎng)技術(shù)中的一個(gè)重要部分是在單片 上實(shí)現(xiàn) TCP/IP 協(xié)議?,F(xiàn)在可獲得的 TCP/
    發(fā)表于 12-17 16:11 ?9次下載

    TCP/IP協(xié)議之路由器簡要分析

    讀完這個(gè)系列的第一篇淺談TCP/IP協(xié)議(一)入門知識(shí)和第二篇淺談TCP/IP
    發(fā)表于 10-10 11:46 ?1次下載

    Microchip TCP/IP協(xié)議

    的開發(fā)人員可以很容易找到許多Microchip產(chǎn)品的商業(yè)和非商業(yè)的TC P/IP實(shí)現(xiàn)方案。本應(yīng)用筆記詳細(xì)說明了Microchip公司自己免費(fèi)提供的TC P/IP協(xié)議。 Microch
    發(fā)表于 04-20 16:04 ?5次下載
     Microchip <b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>

    介紹tcp_ip協(xié)議lwip的特點(diǎn)

    簡介了嵌入式tcp_ip協(xié)議lwip的基本信息
    的頭像 發(fā)表于 07-03 13:05 ?3950次閱讀

    Microchip TCP/IP精簡協(xié)議

    本應(yīng)用筆記描述 Microchip 傳輸控制協(xié)議 / 互聯(lián)網(wǎng)協(xié)議TCP/IP)精簡協(xié)議庫的結(jié)
    發(fā)表于 04-01 15:36 ?18次下載
    Microchip <b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b>精簡<b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>

    Microchip TCP/IP協(xié)議

    。感興趣的開發(fā)人員可以很容易找到許多 Microchip 產(chǎn)品的商業(yè)和非商業(yè)的TCP/IP 實(shí)現(xiàn)方案。本應(yīng)用筆記詳細(xì)說明了 Microchip 公司自己免費(fèi)提供的 TCP/IP
    發(fā)表于 04-02 14:28 ?22次下載
    Microchip <b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>

    Linux網(wǎng)絡(luò)技術(shù)中最核心的部分--TCP/IP協(xié)議

    今天給大家介紹Linux網(wǎng)絡(luò)技術(shù)中最核心的部分--TCP/IP協(xié)議 。 我們先看一下抽象的網(wǎng)絡(luò)協(xié)議
    的頭像 發(fā)表于 06-29 15:14 ?2546次閱讀

    到底什么是TCP/IP協(xié)議,看完這篇你就明白!

    一談到TCP/IP協(xié)議,相信不少小白都處于暴躁的邊緣,只懂其一不知其二。沒關(guān)系,看完這篇你就知道啦!我們先簡單了解下TCP/
    的頭像 發(fā)表于 12-09 15:21 ?1830次閱讀
    到底什么是<b class='flag-5'>TCP</b>/<b class='flag-5'>IP</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>,看完這篇你就明白!

    Microchip TCP/IP 協(xié)議應(yīng)用筆記

    電子發(fā)燒友網(wǎng)站提供《Microchip TCP/IP 協(xié)議應(yīng)用筆記.pdf》資料免費(fèi)下載
    發(fā)表于 04-17 14:16 ?3次下載

    TCP/IP協(xié)議的設(shè)計(jì)與實(shí)現(xiàn)_中文

    電子發(fā)燒友網(wǎng)站提供《TCP/IP協(xié)議的設(shè)計(jì)與實(shí)現(xiàn)_中文.pdf》資料免費(fèi)下載
    發(fā)表于 07-03 11:28 ?4次下載

    LwIP協(xié)議源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《LwIP協(xié)議源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 07-03 11:22 ?3次下載