原始碼分析 socket的建立

2021-08-04 04:15:31 字數 3638 閱讀 7660

這節主要介紹下socket建立的大致流程,我們只關注總體流程,流程總有很多細節,我們暫不去討論,隨著閱讀原始碼量的增加,這些細節問題會迎刃而解,有些機制會在後續其他章節介紹,以免影響此節主要內容分析。

下面是建立socket的主體流程。

static

int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern)

從上面的內容可以看出,create_socket 主體就兩個流程: sock_alloc 以及pf->create鉤子函式。下面具體分析

static

struct socket *sock_alloc(void)

1.1 new_inode

從檔案系統中獲取socket相關的inode節點。

new_inode->alloc_inode->sock_alloc_inode[sb->s_op->alloc_inode]

struct socket_alloc ;

static

struct inode *sock_alloc_inode(struct super_block *sb)

其中sock_inode_cachep變數就是穿件的cache物件,在init函式中會通過kmem_cache_create來建立,可以通過下面的命令檢視分配的情況

root@ubuntu

:/# cat /proc/slabinfo | grep sock_inode_cache

sock_inode_cache 175

175640254

: tunables 000

: slabdata 7

70

1.2 sock_i
static

inline

struct socket *socket_i(struct inode *inode)

#define container_of(ptr, type, member) ()

#define offsetof(type, member) ((size_t)&((type *)0 -> member)

對於這個技巧用的還是比較多的,常見如鍊表,一般會將鍊錶的結構體放在物件裡面,知道了鍊錶節點位址,將其轉換為對應物件的位址。

2.1 協議族函式註冊

以af_inet(af_inet.c)協議為例

fs_initcall(inet_init); //將inet_init安裝到initcall中去
關於initcall以後再學習介紹。// todo

通過這樣的註冊,linux在初始化的時候會執行inet_init()函式,下面分析下這個函式:

static

int __init inet_init(void)

int sock_register(const

struct net_proto_family *ops)

static

struct net_proto_family inet_family_ops = ;

到這裡,我麼就清楚上面pf->create指的是什麼了

2.2 協議結構體初始化

static

int inet_create(struct net *net, struct socket *sock, int protocol)

else

if (ipproto_ip == answer->protocol)

break;

}err = -eprotonosupport;

}/* upon startup we insert all the elements in inetsw_array into

* the linked list inetsw.

*/static

struct inet_protosw inetsw_array =

, ,

};

上面這段**根據型別和協議在inetsw_array陣列中找到對應的協議處理介面。可以反映為什麼在建立socket時,第三個引數protocal可以為0(ipproto_ip)。關於註冊邏輯可以檢視inet_register_protosw

if (unlikely(err))  else

goto out_rcu_unlock;

}... sock->ops = answer->ops;

answer_prot = answer->prot; // 傳輸層使用的協議結構(socket layer -> transport layer inte***ce)

answer_no_check = answer->no_check;

answer_flags = answer->flags;

rcu_read_unlock();

warn_on(answer_prot->slab == null);

err = -enobufs;

sk = sk_alloc(net, pf_inet, gfp_kernel, answer_prot); // 返回sock指標,實際上分配的是tcp_sock(第乙個元素是inet_connection_sock, 而inet_connection_sock 第乙個元素是inet_sock, 同時inet_sock第乙個元素是sock)

if (sk == null)

goto out;

err = 0;

sk->sk_no_check = answer_no_check;

if (inet_protosw_reuse & answer_flags)

sk->sk_reuse = 1;

inet = inet_sk(sk); // 指標轉換: sock => inet_sock

...

// sock結構資料初始化

sock_init_data(sock, sk);

... // 協議初始化 sk_prot = sk->sk_prot_creator = prot (inetsw_array)

if (sk->sk_prot->init)

...}

這樣,socket結構的初始化工作就完成了,其中涉及的結構體有struct sockstruct socketstruct sk_buffstruct net_sockstruct inet_connect_sock它們之間的關係看下原始碼也就清楚了,這裡也就不展示了。

初始化的總體思路:首先通過sock_alloc進行記憶體資源分配建立sock_alloc(包含socket和vfs_inode),之後呼叫協議族net_families[family]註冊的函式create進行協議初始化的工作,依次初始socket、sock、tcp_sock等結構體資訊。

《追蹤linux tcp/ip **執行》

linux-2.6.32

socket程式設計例項(原始碼)

本例項使用面向連線協議的客戶 伺服器模式,其流程如圖2.3所示 圖2.3 面向連線的應用程式流程圖 伺服器方程式 include include define true 1 main server.sin family af inet server.sin port inaddr any if bi...

跨平台非阻塞SOCKET實現原始碼分析

1.實現linux與windows的共同函式 a.linux平台標頭檔案引用 include include include include include include include include include includeb.windows平台標頭檔案引用 include includ...

spring原始碼分析 spring原始碼分析

1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...