日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux sock结构体,struct socket结构体详解

發布時間:2025/3/20 linux 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux sock结构体,struct socket结构体详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在內核中為什么要有struct socket結構體呢?

struct socket結構體的作用是什么?

下面這個圖,我覺得可以回答以上兩個問題。?

由這個圖可知,內核中的進程可以通過使用struct socket結構體來訪問linux內核中的網絡系統中的傳輸層、網絡層、數據鏈路層。也可以說struct socket是內核中的進程與內核中的網路系統的橋梁。

struct?socket

{

socket_state??state;?//?socket?state

short???type?;?//?socket?type

unsigned?long??flags;?//?socket?flags

struct?fasync_struct??*fasync_list;

wait_queue_head_t?wait;

struct?file?*file;

struct?sock?*sock;??//?socket在網絡層的表示;

const?struct?proto_ops?*ops;

}

struct?socket結構體的類型

enum?sock_type

{

SOCK_STREAM?=?1,?//?用于與TCP層中的tcp協議數據的struct?socket

SOCK_DGRAM??=?2,?//用于與TCP層中的udp協議數據的struct?socket

SOCK_RAW????=?3,?//?raw?struct?socket

SOCK_RDM????=?4,?//可靠傳輸消息的struct?socket

SOCK_SEQPACKET?=?5,//?sequential?packet?socket

SOCK_DCCP???=?6,

SOCK_PACKET?=?10,?//從dev?level中獲取數據包的socket

};

struct?socket?中的flags字段取值:

#define?SOCK_ASYNC_NOSPACE??0

#define?SOCK_ASYNC_WAITDATA?1

#define?SOCK_NOSPACE????????2

#define?SOCK_PASSCRED???????3

#define?SOCK_PASSSEC????????4

我們知道在TCP層中使用兩個協議:tcp協議和udp協議。而在將TCP層中的數據往下傳輸時,要使用網絡層的協議,而網絡層的協議很多,不同的網絡使用不同的網絡層協議。我們常用的因特網中,網絡層使用的是IPV4和IPV6協議。

所以在內核中的進程在使用struct socket提取內核網絡系統中的數據時,不光要指明struct socket的類型(用于說明是提取TCP層中tcp協議負載的數據,還是udp層負載的數據),還要指明網絡層的協議類型(網絡層的協議用于負載TCP層中的數據)。

linux內核中的網絡系統中的網絡層的協議,在linux中被稱為address family(地址簇,通常以AF_XXX表示)或protocol family(協議簇,通常以PF_XXX表示)。

1.創建一個struct socket結構體:

int sock_create(int family, int type, int protocol,

struct socket **res);

int sock_create_kern(int family, int type, int protocol,

struct socket **res);

EXPROT_SYMBOL(sock_create);

EXPROT_SYMBOL(sock_create_kern);

family : 指定協議簇的類型,其值為:PF_XXX或 AF_XXX

type?? :指定要創建的struct socket結構體的類型;

protocol : 一般為0;

res??? : 中存放創建的struct socket結構體的地址;int?sock_create(int?family,?int?type,?int?protocol,?struct?socket?**res)

{

return?__sock_create(current->nsproxy->net_ns,?family,?type,?protocol,?res,?0);

}

int?sock_create_kern(int?family,?int?type,?int?protocol,?struct?socket?**res)

{

return?__sock_create(?&init_net,?family,?type,?protocot,?res,?1?);

}

如果在內核中創建struct?socket時,推薦使用sock_create_kern()函數;

//?網絡協議簇結構體

struct?net_proto_family

{

int?family?;?//?協議簇

int?(*create)(struct?net?*net,?struct?socket?*sock,??int?protocol);

struct?module??*owner;

};

內核中的所有的網絡協議的響應的網絡協議簇結構體都存放在?net_families[]指針數組中;

static?struct?net_proto_family?*net_families[NPROTO];

static?int?__sock_create(struct?net?*net,?int?family,?int?type,?int?protocol,

struct?socket?**res,?int?kern?)

{

struct?socket?*sock;

struct?net_proto_family?*pf;

sock?=?sock_alloc();//分配一個struct?socket?結構體

sock->type?=?type;

pf?=?rcu_dereference(net_families[family]);?//獲取相應的網絡協議簇結構體的地址;

pf->create(net,?sock,?protocol);?//?對struct?socket結構體做相應的處理;

*res?=?sock;?//?res中保存創建的struct?socket結構體的地址;

return?0;

}

struct?socket_alloc

{

struct?socket?socket?;

struct?inode?vfs_node?;

}

static?inline?struct?socket?*SOCKET_I(struct?inode?*inode)

{

return?&contain_of(inode,?struct?socket_alloc,?vfs->node)->socket;

}

static?struct?socket?*sock_alloc(void)

{

struct?inode?*inode;

struct?socket?*sock;

inode?=?new_inode(sock_mnt->mnt_sb);//分配一個新的struct?inode節點

sock?=?SOCKET_I(inode);

inode->i_mode?=?S_IFSOCK?|?S_IRWXUGO;//設置inode節點的權限

inode->i_uid?=?current_fsuid();?//?設置節點的UID

inode->i_gid?=?current_fsgid();?//設置節點的GID

return?sock;

}

有以上的代碼可知:linux內核在使用sock_create()、sock_create_kern()

進行struct socket結構體的創建時,其本質是分配了一個struct socket_alloc

結構體,而這個struct socket_alloc結構體中包含了struct socket 和struct

inode(struct inode結構體,是linux內核用來刻畫一個存放在內存中的文件的,通過將struct inode 和 struct socket綁定在一起形成struct socket_alloc結構體,來表示內核中的網絡文件)。然后對分配的struct socket結構體進行初始化,來定義內核中的網絡文件的類型(family, type, protocol).

在linux網絡系統中還有兩個非常重要的套接字地址結構體:

struct sockaddr_in

struct sockaddr;typedef?unsigned?short?sa_family_t;

//?Internet?Address

struct?in_addr{

__b32?s_addr;

}

//struct?describing?an?Internet?socket?address

//sockaddr_in?中存放端口號、網路層中的協議類型(ipv4,ipv6)等,網絡層的IP地址;

struct?sockaddr_in

{

sa_family_t?sin_family?;?//?Address?family?AF_XXX

__be16??????sin_port???;?//?端口號

struct?in_addr?sin_addr?;?//?Internet?Address

/*Pad?to?size?of??'struct?sockaddr'*/

...........

};

//套接字地址結構體。

struct?sockaddr

{

sa_family_t?sa_family;?//?存放網絡層所使用的協議類型(AF_XXX?或?PF_XXX);

char?sa_data[14];???//?里面存放端口號、網絡層地址等信息;

}

從本質上來說,struct sockaddr與struct sockaddr_in是相同的。

但在,實際的使用過程中,struct sockaddr_in是 Internet環境下的套接字地址形式,而struct sockaddr是通過的套接字地址個形式。在linux內核中struct sockaddr使用的更多,目的是使linux內核代碼更為通用。

struct sockaddr_in 可以與 struct sockaddr 進行自由的轉換。

2.將創建的套接字(struct socket)與套接字地址結構體(struct sockaddr or struct sockaddr_in)進行綁定:

int kernel_bind(struct socket *sock, struct sockaddr *addr,

int addrlen)

EXPROT_SYMBOL(kernel_bind);

sock : 為通過sock_create()或sock_create_kern()創建的套接字;

addr : 為套接字地址結構體;

addrlen:為套接字地址結構體的大小;

3.將一個套接字(struct socket)設置為監聽狀態:

int kernel_listen(struct socket *sock, int backlog);

backlog :一般情況下設置為0;

EXPORT_SYMBOL(kernel_listen);

4.當把一個套接字設置為監聽狀態以后,使用這個套接字去監聽其它的套接字;

int kernel_accept(struct socket *sock, struct socket **new_sock,

int flags);

EXPORT_SYMBOL(kernel_accept);

sock : listening socket 處于監聽狀態的套接字;

new_sock : 被監聽的套接字;

flags: struct socket中的flags字段的取值;

5.把一個套接字連接到另一個套接字地址結構體上:

int kernel_connect(struc socket *sock, struct sockaddr *addr,

int addrlen, int flags);

EXPORT_SYMBOL(kernel_connect);

sock : struct socket;

addr : 為另一個新的套接字地址結構體;

addrlen : 套接字地址結構體的大小;

flags :file-related flags associated with socket

6.把一個應用層中的數據發送給另一個設備中的進程:

int kernel_sendmsg(struct socket *sock, struct msghdr *msg,

struct kvec *vec, size_t num, size_t size)

EXPORT_SYMBOL(kernel_sendmsg);

sock : 為當前進程中的struct socket套接字;

msg? : 用于接收來自應用層的數據包;

kvec : 中存放將要發送出去的數據;

num? : 見代碼;

size : 為將要發送的數據的長度;

struct?iovec

{

void?__user?*iov_base;

__kernel_size_t?iov_len;

}

struct?msghdr

{

//用于存放目的進程所使用的套接字地址

void?*msg_name;??//?用于存放目的進程的struct?sockaddr_in

int???msg_namelen;?//?目的進程的sizeof(struct?sockaddr_in)

//用于來自應用層的數據

struct?iovec?*msg_iov?;//?指向一個struct?iovec的數組,數組中的每個成員表示一個數據塊

__kernel_size_t??msg_iovlen?;?//數據塊數,即struct?iovec數組的大小

//用于存放一些控制信息

void?*msg_control?;

__kernel_size_t?msg_controllen;?//控制信息的長度;

//

int?msg_flags;

}

struct?kvec

{

void?*iov_base;?//用于存放來自應用層的數據;

size_t?iov_len;?//來自應用層的數據的長度;

}

struct msghdr中的flags字段的取值為:

int kernel_sendmsg(struct socket *sock, struct msghdr *msg,

struct kvec *vec, size_t num, size_t size)函數的實現為:

有kernel_sendmsg()的實現代碼可知,struct kvec中的數據部分最終還是要放到struct msghdr之中去的。

kernel_sendmsg()的用法:

也可以使用下面這個函數來實現相同的功能:

int sock_sendmsg(struct socket *sock, struct msghdr *msg,

size_t size);

EXPORT_SYMBOL(sock_sendmsg);

7.接受來自另一個網絡進程中的數據:

int kernel_recvmsg(struct socket *sock, struct msghdr *msg,

struct kvec *vec, size_t num, size_t size, int flags)

EXPORT_SYMBOL(kernel_recvmsg);

sock : 為接受進程的套接字;

msg? : 用于存放接受到的數據;

vec? : 用于指向本地進程中的緩存區;

num? : 為數據塊的塊數;

size : 緩存區的大小;

flags: struct msghdr中的flags字段中的取值范圍;

int kernel_recvmsg()的實現:

kernel_recvmsg()的用法:

8.關閉一個套接字:

void sock_release(struct socket *sock);

用于關閉一個套接字,并且如果一個它struct socket綁定到了一個struct

inode節點上的話,相應的struct inode也會被釋放。

以上這些函數位于linux源代碼包中的/net/socket.c之中。

總結

以上是生活随笔為你收集整理的linux sock结构体,struct socket结构体详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。