九色91_成人精品一区二区三区中文字幕_国产精品久久久久一区二区三区_欧美精品久久_国产精品99久久久久久久vr_www.国产视频

Hello! 歡迎來到小浪云!


Linux內(nèi)核 | socket底層的來龍去脈


avatar
小浪云 2025-01-03 153

本文在上文基礎(chǔ)上進一步全面分析socket底層的相關(guān)實現(xiàn)。

一、socket與inode

socket在Linux中對應(yīng)的文件系統(tǒng)叫Sockfs,每創(chuàng)建一個socket,就在sockfs中創(chuàng)建了一個特殊的文件,同時創(chuàng)建了sockfs文件系統(tǒng)中的inode,該inode唯一標識當前socket的通信。

如下圖所示,左側(cè)窗口使用nc工具創(chuàng)建一個TCP連接;右側(cè)找到該進程id(3384),通過查看該進程下的描述符,可以看到”3 ->socket:[86851]”,socket表示這是一個socket類型的fd,[86851]表示這個一個inode號,能夠唯一標識當前的這個socket通信連接,進一步在該inode下查看”grep -i “86851” /proc/net/tcp”可以看到該TCP連接的所有信息(連接狀態(tài)、IP地址等),只不過是16進制顯示。

Linux內(nèi)核 | socket底層的來龍去脈

在分析socket與inode之前,先通過ext4文件系統(tǒng)舉例:

在VFS層,即抽象層,所有的文件系統(tǒng)都使用struct inode結(jié)構(gòu)體描述indoe,然而分配inode的方式都不同,如ext4文件系統(tǒng)的分配inode函數(shù)是ext4_alloc_inode,如下所示:

static?Struct?inode?*ext4_alloc_inode(struct?super_block?*sb) { ?struct?ext4_inode_info?*ei;  ?ei?=?kmem_cache_alloc(ext4_inode_cachep,?GFP_NOFS); ?if?(!ei) ??return?NULL;  ?ei->vfs_inode.i_version?=?1; ?spin_lock_init(&ei->i_raw_lock); ?INIT_LIST_HEAD(&ei->i_prealloc_list); ?spin_lock_init(&ei->i_prealloc_lock); ?ext4_es_init_tree(&ei->i_es_tree); ?rwlock_init(&ei->i_es_lock); ?INIT_LIST_HEAD(&ei->i_es_list); ?ei->i_es_all_nr?=?0; ?ei->i_es_shk_nr?=?0; ?ei->i_es_shrink_lblk?=?0; ?ei->i_reserved_data_blocks?=?0; ?ei->i_da_metadata_calc_len?=?0; ?ei->i_da_metadata_calc_last_lblock?=?0; ?spin_lock_init(&(ei->i_block_reservation_lock)); #ifdef?CONFIG_QUOTA ?ei->i_reserved_quota?=?0; ?memset(&ei->i_dquot,?0,?sizeof(ei->i_dquot)); #endif ?ei->jinode?=?NULL; ?INIT_LIST_HEAD(&ei->i_rsv_conversion_list); ?spin_lock_init(&ei->i_completed_io_lock); ?ei->i_sync_tid?=?0; ?ei->i_datasync_tid?=?0; ?atomic_set(&ei->i_unwritten,?0); ?INIT_WORK(&ei->i_rsv_conversion_work,?ext4_end_io_rsv_work); ?return?&ei->vfs_inode; } 

從函數(shù)中可以看出來,函數(shù)其實是調(diào)用kmem_cache_alloc分配了 ext4_inode_info結(jié)構(gòu)體結(jié)構(gòu)體如下所示),然后進行了一系列的初始化,最后返回的卻是struct inode結(jié)構(gòu)體(如上面代碼的return &ei->vfs_inode)。如下結(jié)構(gòu)體ext4_inode_info(ei)所示,vfs_inode是其struct inode結(jié)構(gòu)體成員。

struct?ext4_inode_info?{ ?__le32?i_data[15];?/*?unconverted?*/ ?__u32?i_dtime; ?ext4_fsblk_t?i_file_acl;  ?...... ?struct?rw_semaphore?i_data_sem; ?struct?rw_semaphore?i_mmap_sem; ?struct?inode?vfs_inode; ?struct?jbd2_inode?*jinode; ??...... }; 

Linux內(nèi)核 | socket底層的來龍去脈

再看一下:ext4_inode、ext4_inode_info、inode之間的關(guān)聯(lián),

ext4_inode如下所示,是磁盤上inode的結(jié)構(gòu)

struct?ext4_inode?{ ?__le16?i_mode;??/*?File?mode?*/ ?__le16?i_uid;??/*?Low?16?bits?of?Owner?Uid?*/ ?__le32?i_size_lo;?/*?Size?in?bytes?*/ ?__le32?i_atime;?/*?Access?time?*/ ?__le32?i_ctime;?/*?Inode?Change?time?*/ ?__le32?i_mtime;?/*?Modification?time?*/ ?__le32?i_dtime;?/*?Deletion?Time?*/ ?__le16?i_gid;??/*?Low?16?bits?of?Group?Id?*/ ?__le16?i_links_count;?/*?Links?count?*/ ?__le32?i_blocks_lo;?/*?Blocks?count?*/ ?__le32?i_flags;?/*?File?flags?*/ ?...... } 

ext4_inode_info是ext4文件系統(tǒng)的inode在內(nèi)存中管理結(jié)構(gòu)體:

struct?ext4_inode_info?{ ?__le32?i_data[15];?/*?unconverted?*/ ?__u32?i_dtime; ?ext4_fsblk_t?i_file_acl; ?...... }; 

inode是文件系統(tǒng)抽象層:

struct?inode?{ ????umode_t?????????????????i_mode; ????unsigned?short??????????i_opflags; ????kuid_t??????????????????i_uid; ????kgid_t??????????????????i_gid; ????unsigned?int????????????i_flags; ? ????/*?對inode操作的具體方法 ?????*?不同的文件系統(tǒng)會注冊不同的函數(shù)方法即可 ?????*/ ????const?struct?inode_operations???*i_op; ????struct?super_block??????*i_sb; ????struct?address_space????*i_mapping; ? ????unsigned?long???????????i_ino; ???? ????union?{ ????????const?unsigned?int?i_nlink; ????????unsigned?int?__i_nlink; ????}; ????dev_t???????????????????i_rdev; ????/*?文件大小?*/ ????loff_t??????????????????i_size; ????/*?文件最后訪問時間?*/ ????struct?timespec?????????i_atime; ????/*?文件最后修改時間?*/ ????struct?timespec?????????i_mtime; ????/*?文件創(chuàng)建時間?*/ ????struct?timespec?????????i_ctime; ????spinlock_t??????????????i_lock;?/*?i_blocks,?i_bytes,?maybe?i_size?*/ ????unsigned?short??????????i_bytes; ????unsigned?int????????????i_blkbits; ????enum?rw_hint????????????i_write_hint; ????blkcnt_t????????????????i_blocks;  ????/*?Misc?*/ ????unsigned?long???????????i_state; ????struct?rw_semaphore?????i_rwsem; ????unsigned?long???????????dirtied_when;???/*?jiffies?of?first?dirtying?*/ ????unsigned?long???????????dirtied_time_when; ? ????/*?inode通過以下結(jié)構(gòu)被加入到的各種鏈表?*/ ????struct?hlist_node???????i_hash; ????struct?list_head????????i_io_list;??????/*?backing?dev?IO?list?*/ ? ????struct?list_head????????i_lru;??????????/*?inode?LRU?list?*/ ????struct?list_head????????i_sb_list; ????struct?list_head????????i_wb_list;??????/*?backing?dev?writeback?list?*/ ????union?{ ????????struct?hlist_head???????i_dentry; ????????struct?rcu_head?????????i_rcu; ????}; ????atomic64_t??????????????i_version; ????atomic_t????????????????i_count; ????atomic_t????????????????i_dio_count; ????atomic_t????????????????i_writecount; ? ????/*?對文件操作(如文件讀寫等)的具體方法 ?????*?實現(xiàn)虛擬文件系統(tǒng)的核心結(jié)構(gòu) ?????*?不同的文件系統(tǒng)只需要注冊不同的函數(shù)方法即可 ?????*/ ????const?struct?file_operations????*i_fop;?/*?former?->i_op->default_file_ops?*/ ????struct?file_lock_context????????*i_flctx; ????struct?address_space????i_data; ????struct?list_head????????i_devices; ????union?{ ????????struct?pipe_inode_info??*i_pipe; ????????struct?block_device?????*i_bdev; ????????struct?cdev?????????????*i_cdev; ????????char????????????????????*i_link; ????????unsigned????????????????i_dir_seq; ????}; ????__u32???????????????????i_generation;  ????void????????????????????*i_private;?/*?fs?or?device?private?pointer?*/ }?__randomize_layout; 

三者的關(guān)系如下圖,struct inode是VFS抽象層的表示,ext4_inode_info是ext4文件系統(tǒng)inode在內(nèi)存中的表示,struct ext4_inode是文件系統(tǒng)inode在磁盤中的表示。

Linux內(nèi)核 | socket底層的來龍去脈

VFS采用c語言的方式實現(xiàn)了struct inode和struct ext4_inode_info繼承關(guān)系,inode與ext4_inode_info是父類子類的關(guān)系,并且Linux內(nèi)核實現(xiàn)了inode與ext4_inode_info父子類的互相轉(zhuǎn)換,如下EXT4_I所示:

static?inline?struct?ext4_inode_info?*EXT4_I(struct?inode?*inode) { ?return?container_of(inode,?struct?ext4_inode_info,?vfs_inode); } 

以上是以ext4為例進行了分析,下面將開始從socket與inode進行分析:

sockfs是虛擬文件系統(tǒng),所以在磁盤上不存在inode的表示,在內(nèi)核中有struct socket_alloc來表示內(nèi)存中sockfs文件系統(tǒng)inode的相關(guān)結(jié)構(gòu)體:

struct?socket_alloc?{ ?struct?socket?socket; ?struct?inode?vfs_inode; }; 

struct socket與struct inode的關(guān)系如下圖,正如ext4文件系統(tǒng)中struct ext4_inode_info與struct inode的關(guān)系類似,inode和socket_alloc結(jié)構(gòu)體是父類子類的關(guān)系。

Linux內(nèi)核 | socket底層的來龍去脈

從上面分析ext4文件系統(tǒng)分配inode時,是通過ext4_alloc_inode函數(shù)分配了ext4_inode_info結(jié)構(gòu)體,并初始化結(jié)構(gòu)體成員,函數(shù)最后返回的是ext4_inode_info中的struct inode成員。sockfs文件系統(tǒng)也類似,sockfs文件系統(tǒng)分配inode時,創(chuàng)建的是socket_alloc結(jié)構(gòu)體,在函數(shù)最后返回的是struct inode。

從上篇文章中,分析了sockfs文件系統(tǒng)注冊與掛載,初始化了超級塊的函數(shù)操作集,如下所示alloc_inode是分配inode結(jié)構(gòu)體的回調(diào)函數(shù)接口

static?const?struct?super_operations?sockfs_ops?=?{ ?.alloc_inode?=?sock_alloc_inode, ?.destroy_inode?=?sock_destroy_inode, ?.statfs??=?simple_statfs, } 

sockfs文件系統(tǒng)的inode分配函數(shù)是sock_alloc_inode,如下所示:

static?struct?inode?*sock_alloc_inode(struct?super_block?*sb) { ?struct?socket_alloc?*ei; ?struct?socket_wq?*wq;  ?ei?=?kmem_cache_alloc(sock_inode_cachep,?GFP_KERNEL); ?if?(!ei) ??return?NULL; ?wq?=?kmalloc(sizeof(*wq),?GFP_KERNEL); ?if?(!wq)?{ ??kmem_cache_free(sock_inode_cachep,?ei); ??return?NULL; ?} ?init_waitqueue_head(&wq->wait); ?wq->fasync_list?=?NULL; ?wq->flags?=?0; ?RCU_INIT_POINTER(ei->socket.wq,?wq);  ?ei->socket.state?=?SS_UNCONNECTED; ?ei->socket.flags?=?0; ?ei->socket.ops?=?NULL; ?ei->socket.sk?=?NULL; ?ei->socket.file?=?NULL;  ?return?&ei->vfs_inode; } 

sock_alloc_inode函數(shù)分配了socket_alloc結(jié)構(gòu)體,也就意味著分配了struct socket和struct inode,并最終返回了socket_alloc結(jié)構(gòu)體成員inode。

故struct socket這個字段出生的時候其實就和一個struct inode結(jié)構(gòu)體伴生出來的,它們倆共同封裝在struct socket_alloc中,由sockfs的sock_alloc_inode函數(shù)分配的,函數(shù)返回的是struct inode結(jié)構(gòu)體.和ext4文件系統(tǒng)類型類似。sockfs文件系統(tǒng)也實現(xiàn)了struct inode與struct socket的轉(zhuǎn)換:

static?inline?struct?socket?*SOCKET_I(struct?inode?*inode) { ?return?&container_of(inode,?struct?socket_alloc,?vfs_inode)->socket; } 

二、socket的創(chuàng)建與初始化

首先看一下struct socket在內(nèi)核中的定義:

struct?socket?{ ?socket_state??state;//socket狀態(tài)  ?short???type;?//socket類型  ?unsigned?long??flags;//socket的標志位  ?struct?socket_wq?__rcu?*wq;  ?struct?file??*file;//與socket關(guān)聯(lián)的文件指針 ?struct?sock??*sk;//套接字的核心,面向底層網(wǎng)絡(luò)具體協(xié)議 ?const?struct?proto_ops?*ops;//socket函數(shù)操作集 }; 

在內(nèi)核中還有struct sock結(jié)構(gòu)體,在struct socket中可以看到那么它們的關(guān)系是什么?

1、socket面向上層,sock面向下層的具體協(xié)議

2、socket是內(nèi)核抽象出的一個通用結(jié)構(gòu)體,主要是設(shè)置了一些跟fs相關(guān)的字段,而真正跟網(wǎng)絡(luò)通信相關(guān)的字段結(jié)構(gòu)體是struct sock

3、struct sock是套接字的核心,是對底層具體協(xié)議做的一層抽象封裝,比如TCP協(xié)議,struct sock結(jié)構(gòu)體中的成員sk_prot會賦值為tcp_prot,udp協(xié)議會賦值為udp_prot。

(關(guān)于更多struct sock的分析將在以后的文章中分析)

創(chuàng)建socket的系統(tǒng)調(diào)用:在用戶空間創(chuàng)建了一個socket后,返回值是一個文件描述符。在SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)最后調(diào)用sock_map_fd進行關(guān)聯(lián),其中返回的就是用戶空間獲取的文件描述符fd,sock就是調(diào)用sock_create創(chuàng)建成功的socket.

SYSCALL_DEFINE3(socket,?int,?family,?int,?type,?int,?protocol) { ?int?retval; ?struct?socket?*sock; ?int?flags;  ?/*?Check?the?SOCK_*?constants?for?consistency.??*/ ?BUILD_BUG_ON(SOCK_CLOEXEC?!=?O_CLOEXEC); ?BUILD_BUG_ON((SOCK_MAX?|?SOCK_TYPE_MASK)?!=?SOCK_TYPE_MASK); ?BUILD_BUG_ON(SOCK_CLOEXEC?&?SOCK_TYPE_MASK); ?BUILD_BUG_ON(SOCK_NONBLOCK?&?SOCK_TYPE_MASK);  ?flags?=?type?&?~SOCK_TYPE_MASK; ?if?(flags?&?~(SOCK_CLOEXEC?|?SOCK_NONBLOCK)) ??return?-EINVAL; ?type?&=?SOCK_TYPE_MASK;  ?if?(SOCK_NONBLOCK?!=?O_NONBLOCK?&&?(flags?&?SOCK_NONBLOCK)) ??flags?=?(flags?&?~SOCK_NONBLOCK)?|?O_NONBLOCK;  ?retval?=?sock_create(family,?type,?protocol,?&sock); ?if?(retval?return?retval;  ?return?sock_map_fd(sock,?flags?&?(O_CLOEXEC?|?O_NONBLOCK)); } 

socket的創(chuàng)建將調(diào)用sock_create函數(shù):

int?sock_create(int?family,?int?type,?int?protocol,?struct?socket?**res) { ?return?__sock_create(current->nsproxy->net_ns,?family,?type,?protocol,?res,?0); } 

__sock_create函數(shù)調(diào)用sock_alloc函數(shù)分配socket結(jié)構(gòu)和文件節(jié)點:

int?__sock_create(struct?net?*net,?int?family,?int?type,?int?protocol, ????struct?socket?**res,?int?kern) { ?int?err; ?struct?socket?*sock; ?const?struct?net_proto_family?*pf; ??//檢查family的字段范圍 ?if?(family?=?NPROTO) ??return?-EAFNOSUPPORT; ?if?(type?type?>=?SOCK_MAX) ??return?-EINVAL;  ?...... ?sock?=?sock_alloc();//分配socket和inode,返回sock ?if?(!sock)?{ ??net_warn_ratelimited("socket:?no?more?sockets "); ??return?-ENFILE;?/*?Not?exactly?a?match,?but?its?the ???????closest?posix?thing?*/ ?}  ?sock->type?=?type; ??...... ?rcu_read_lock(); ?pf?=?rcu_dereference(net_families[family]);//獲取協(xié)議族family對應(yīng)的操作表 ?err?=?-EAFNOSUPPORT; ?if?(!pf) ??goto?out_release;  ?if?(!try_module_get(pf->owner)) ??goto?out_release;  ?/*?Now?protected?by?module?ref?count?*/ ?rcu_read_unlock();  ?err?=?pf->create(net,?sock,?protocol,?kern);//調(diào)用family協(xié)議族的socket創(chuàng)建函數(shù) ?if?(err?if?(!try_module_get(sock->ops->owner)) ??goto?out_module_busy;  ?...... } 

socket結(jié)構(gòu)體的創(chuàng)建在sock_alloc()函數(shù)中:

struct?socket?*sock_alloc(void) { ?struct?inode?*inode; ?struct?socket?*sock;  ?inode?=?new_inode_pseudo(sock_mnt->mnt_sb); ?if?(!inode) ??return?NULL;  ?sock?=?SOCKET_I(inode);  ?inode->i_ino?=?get_next_ino(); ?inode->i_mode?=?S_IFSOCK?|?S_IRWXUGO; ?inode->i_uid?=?current_fsuid(); ?inode->i_gid?=?current_fsgid(); ?inode->i_op?=?&sockfs_inode_ops;  ?this_cpu_add(sockets_in_use,?1); ?return?sock; } 

new_inode_pseudo中通過繼續(xù)調(diào)用sockfs文件系統(tǒng)中的sock_alloc_inode函數(shù)完成struct socket_alloc的創(chuàng)建并返回其結(jié)構(gòu)體成員struct inode。

然后調(diào)用SOCKT_I函數(shù)返回對應(yīng)的struct socket。

在_sock_create中:pf->create(net, sock, protocol, kern);

通過相應(yīng)的協(xié)議族,進一步調(diào)用不同的socket創(chuàng)建函數(shù)。pf是struct net_proto_family結(jié)構(gòu)體,如下所示:

struct?net_proto_family?{ ?int??family; ?int??(*create)(struct?net?*net,?struct?socket?*sock, ??????int?protocol,?int?kern); ?struct?module?*owner; }; 

net_families[]數(shù)組里存放的是各個協(xié)議族的信息,以family字段作為下標,對應(yīng)的值為net_pro_family結(jié)構(gòu)體。此處我們針對TCP協(xié)議分析,因此我們family字段是AF_INET,pf->create將調(diào)用inet_create函數(shù)繼續(xù)完成底層struct sock等創(chuàng)建和初始化。

inet_create函數(shù)完成struct socket、struct inode、struct sock的創(chuàng)建與初始化后,調(diào)用sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));完成socket與文件系統(tǒng)的關(guān)聯(lián),負責分配文件,并與socket進行綁定:

1、調(diào)用sock_alloc_file,分配一個struct file,并將私有數(shù)據(jù)指針指向socket結(jié)構(gòu)

2、fd_install 對應(yīng)文件描述符和file

static?int?sock_map_fd(struct?socket?*sock,?int?flags) { ?struct?file?*newfile; ?int?fd?=?get_unused_fd_flags(flags);//為socket分配文件號和文件結(jié)構(gòu) ?if?(unlikely(fd?return?fd; ?}  ?newfile?=?sock_alloc_file(sock,?flags,?NULL);//分配file對象 ?if?(likely(!IS_ERR(newfile)))?{ ??fd_install(fd,?newfile);//使文件號與文件結(jié)構(gòu)掛鉤 ??return?fd; ?}  ?put_unused_fd(fd); ?return?PTR_ERR(newfile); } 

get_unused_fd_flags(flags)繼續(xù)調(diào)用alloc_fd完成文件描述符的分配。

sock_alloc_file(sock, flags, NULL)分配一個struct file結(jié)構(gòu)體

struct?file?*sock_alloc_file(struct?socket?*sock,?int?flags,?const?char?*dname) { ?...... ?file?=?alloc_file(&path,?FMODE_READ?|?FMODE_WRITE, ????&socket_file_ops);//分配struct?file結(jié)構(gòu)體 ?if?(IS_ERR(file))?{ ??/*?drop?dentry,?keep?inode?for?a?bit?*/ ??ihold(d_inode(path.dentry)); ??path_put(&path); ??/*?...?and?now?kill?it?properly?*/ ??sock_release(sock); ??return?file; ?}  ?sock->file?=?file;?//socket通過其file字段進行關(guān)聯(lián) ?file->f_flags?=?O_RDWR?|?(flags?&?O_NONBLOCK); ?file->private_data?=?sock;//file通過private_data與socket關(guān)聯(lián) ?return?file;?//返回初始化、關(guān)聯(lián)后的file結(jié)構(gòu)體 } 

其中file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
&socket_file_ops);分配了file結(jié)構(gòu)體并進行初始化:

struct?file?*alloc_file(const?struct?path?*path,?fmode_t?mode, ??const?struct?file_operations?*fop) { ?struct?file?*file;  ?file?=?get_empty_filp(); ?if?(IS_ERR(file)) ??return?file;  ?file->f_path?=?*path; ?file->f_inode?=?path->dentry->d_inode; ?file->f_mapping?=?path->dentry->d_inode->i_mapping; ?file->f_wb_err?=?filemap_sample_wb_err(file->f_mapping); ?if?((mode?&?FMODE_READ)?&& ??????likely(fop->read?||?fop->read_iter)) ??mode?|=?FMODE_CAN_READ; ?if?((mode?&?FMODE_WRITE)?&& ??????likely(fop->write?||?fop->write_iter)) ??mode?|=?FMODE_CAN_WRITE; ?file->f_mode?=?mode; ?file->f_op?=?fop; ?if?((mode?&?(FMODE_READ?|?FMODE_WRITE))?==?FMODE_READ) ??i_readcount_inc(path->dentry->d_inode); ?return?file; } 

其中file->f_op = fop,將socket_file_ops傳遞給文件操作表

static?const?struct?file_operations?socket_file_ops?=?{ ?.owner?=?THIS_MODULE, ?.llseek?=?no_llseek, ?.read_iter?=?sock_read_iter, ?.write_iter?=?sock_write_iter, ?.poll?=??sock_poll, ?.unlocked_ioctl?=?sock_ioctl, #ifdef?CONFIG_COMPAT ?.compat_ioctl?=?compat_sock_ioctl, #endif ?.mmap?=??sock_mmap, ?.release?=?sock_close, ?.fasync?=?sock_fasync, ?.sendpage?=?sock_sendpage, ?.splice_write?=?generic_splice_sendpage, ?.splice_read?=?sock_splice_read, }; 

以上操作完成了struct socket、struct sock、struct file等的創(chuàng)建、初始化、關(guān)聯(lián),并最終返回socket描述符fd

Linux內(nèi)核 | socket底層的來龍去脈

socket描述符fd和我們平時操作文件的文件描述符相同,那么會有一個疑問,可以看到struct file_operations socket_file_ops函數(shù)表中并沒有提供write()和read()接口,只是看到read_iter,write_iter等接口,那么系統(tǒng)是如何處理的呢?

以write()為例:

sys_write()->__vfs_write()

ssize_t?__vfs_write(struct?file?*file,?const?char?__user?*p,?size_t?count, ??????loff_t?*pos) { ?if?(file->f_op->write)//如果文件函數(shù)表結(jié)構(gòu)體提供了write接口函數(shù) ??return?file->f_op->write(file,?p,?count,?pos);//調(diào)用它的write函數(shù) ?else?if?(file->f_op->write_iter) ??return?new_sync_write(file,?p,?count,?pos);//否則調(diào)用new_sync_write函數(shù) ?else ??return?-EINVAL; } 

從__vfs_write函數(shù)中可以看出來,如果socket函數(shù)表中沒有提供write接口函數(shù),則調(diào)用new_sync_write:

static?ssize_t?new_sync_write(struct?file?*filp,?const?char?__user?*buf,?size_t?len,?loff_t?*ppos) { ?......  ?ret?=?call_write_iter(filp,?&kiocb,?&iter); ?...... } 

call_write_iter:

static?inline?ssize_t?call_write_iter(struct?file?*file,?struct?kiocb?*kio,struct?iov_iter?*iter) { ?return?file->f_op->write_iter(kio,?iter);//調(diào)用socket文件函數(shù)表的aio_write函數(shù) } 

從以上__vfs_write()分析,如果文件函數(shù)表結(jié)構(gòu)提供了write接口函數(shù)則調(diào)用write函數(shù),如果文件函數(shù)表結(jié)構(gòu)沒有提供write接口函數(shù)(如socket操作函數(shù)表中沒有提供write接口),則調(diào)用write_iter接口,即調(diào)用socket操作函數(shù)表中的sock_write_iter。就這樣通過socket fd進行普通文件系統(tǒng)那樣通過描述符進行讀寫等。

用戶得到socket fd,可以進行地址綁定、發(fā)送以及接收數(shù)據(jù)等操作,在Linux內(nèi)核中有相關(guān)的函數(shù)完成從socket fd到struct socket、struct file的轉(zhuǎn)換:

static?struct?socket?*sockfd_lookup_light(int?fd,?int?*err,?int?*fput_needed) { ?struct?fd?f?=?fdget(fd);//通過socket?fd獲取struct?fd結(jié)構(gòu)體,struct?fd結(jié)構(gòu)體中有struct?file結(jié)構(gòu) ?struct?socket?*sock;  ?*err?=?-EBADF; ?if?(f.file)?{ ??sock?=?sock_from_file(f.file,?err);//通過獲取的struct?file結(jié)構(gòu)體獲取相應(yīng)的struct?socket指針 ??if?(likely(sock))?{ ???*fput_needed?=?f.flags; ???return?sock; ??} ??fdput(f); ?} ?return?NULL; } 

fdget()函數(shù)從當前進程的files_struct結(jié)構(gòu)中找到網(wǎng)絡(luò)文件系統(tǒng)中的file文件指針,并封裝在struct fd結(jié)構(gòu)體中。sock_from函數(shù)通過得到的file結(jié)構(gòu)體得到對應(yīng)的socket結(jié)構(gòu)指針。sock_from函數(shù)如下:

struct?socket?*sock_from_file(struct?file?*file,?int?*err) { ?if?(file->f_op?==?&socket_file_ops) ??return?file->private_data;?/*?set?in?sock_map_fd?*/  ?*err?=?-ENOTSOCK; ?return?NULL; } 

至此,socket底層來龍去脈的大體結(jié)構(gòu)大概就分析到這,最為核心的struct sock相關(guān)的聯(lián)系以及底層協(xié)議的初始化等將在以后的文章進行分析。

相關(guān)閱讀

主站蜘蛛池模板: www.久久| 欧美日韩综合一区 | 影音先锋成人资源 | 国产精品视频一区二区三区 | 国产精品高潮呻吟久久 | 日韩精品一区二区久久 | 欧美亚洲免费 | 毛片毛片毛片毛片 | 午夜视频在线观看视频 | 福利久久| 欧美aaaaa | 在线亚洲欧美 | 欧美性一区二区三区 | 欧美黄色精品 | 亚洲图片一区二区三区 | 欧美午夜视频 | 中文字幕视频在线观看 | 日韩精品一区二区三区视频播放 | 啪啪网页 | 久久久久久国产精品 | 国产乱码精品一区二区三区中文 | 亚洲a人| 成人黄色在线 | 日本久久久久久 | 国产成人免费视频网站高清观看视频 | 狠狠色网 | 欧美福利视频 | 精品免费国产视频 | 五月天天丁香婷婷在线中 | 亚洲视频观看 | 91免费看片 | 黑人巨大精品欧美一区二区免费 | 免费成人av | 尤物在线 | 亚洲精品福利视频 | 色www精品视频在线观看 | 久久精品国产一区二区电影 | 美女久久久久久久久 | 欧美a级网站| 99热首页 | 中文字幕高清av |