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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

套接口学习(一)实现

發(fā)布時間:2024/6/21 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 套接口学习(一)实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? 套接口這個概念最先由4.2BSD(1983)引入。如今已經(jīng)成為一個通用的網(wǎng)絡(luò)應(yīng)用程序編程接口。受到全部操作系統(tǒng)的支持。套接口層位于應(yīng)用程序和 協(xié)議棧之間,相應(yīng)用程序屏蔽了與協(xié)議相關(guān)實(shí)現(xiàn)的詳細(xì)細(xì)節(jié)。

? 通常,應(yīng)用程序中調(diào)用庫函數(shù)。而庫函數(shù)通過系統(tǒng)調(diào)用進(jìn)入套接口層,Linux的套接口層實(shí)現(xiàn)提供了一組專門的套接口系統(tǒng)調(diào)用。分別在相應(yīng)的庫函數(shù)名之上加上"sys_"前綴。此外為了體現(xiàn)一切皆文件的理念。Linux也同意標(biāo)準(zhǔn)I/O系統(tǒng)調(diào)用通過一個套接口文件描寫敘述符來讀寫其相應(yīng)套接口上的網(wǎng)絡(luò)連接。就像通過文件描寫敘述符訪問一個已經(jīng)打開的普通文件一樣。

套接口在創(chuàng)建時。即與一個文件及一個文件描寫敘述符綁定,此后全部對該套接口的操作都是通過與其綁定的文件描寫敘述符進(jìn)行的,包含專門的套接口系統(tǒng)調(diào)用。頁包含標(biāo)準(zhǔn)的I/O系統(tǒng)調(diào)用對套接口的操作,與套接口綁定的文件類型為套接口文件。


套接口層的調(diào)用涉及下面文件:

include/linux/net.h ?定義套接口層相關(guān)的結(jié)構(gòu)、宏和函數(shù)原型

include/net/sock.h ? 定義主要的傳輸控制塊結(jié)構(gòu)、宏和函數(shù)原型

net/socket.c ?實(shí)現(xiàn)套接口層的系統(tǒng)調(diào)用

net/ipv4/af_inet.c 網(wǎng)絡(luò)層和傳輸層接口

socket結(jié)構(gòu)

struct socket {socket_state state;kmemcheck_bitfield_begin(type);short type;kmemcheck_bitfield_end(type);unsigned long flags;/** Please keep fasync_list & wait fields in the same cache line*/struct fasync_struct *fasync_list;wait_queue_head_t wait;struct file *file;struct sock *sk;const struct proto_ops *ops; };state

用于表示所在套接口所處的狀態(tài)標(biāo)志。該標(biāo)志有些狀態(tài)僅僅對TCP套接口有意義,由于僅僅有TCP是面向連接的協(xié)議

typedef enum {
SS_FREE = 0, /* not allocated */
SS_UNCONNECTED, /* unconnected to any socket */
SS_CONNECTING, /* in process of connecting */
SS_CONNECTED, /* connected to socket */
SS_DISCONNECTING /* in process of disconnecting */
} socket_state;

type

套接口類型

enum sock_type {
SOCK_STREAM = 1, 基于連接的套接口
SOCK_DGRAM = 2, 基于數(shù)據(jù)報的套接口
SOCK_RAW = 3, 原始套接口
SOCK_RDM = 4, 可靠傳送報文套接口
SOCK_SEQPACKET = 5, 順序分組套接口
SOCK_DCCP = 6, 數(shù)據(jù)報擁塞控制協(xié)議套接口
SOCK_PACKET = 10,混雜模式套接口
};

flags

一組標(biāo)志位

#define SOCK_ASYNC_NOSPACE 0 ?該套接口發(fā)送隊(duì)列是否已滿
#define SOCK_ASYNC_WAITDATA 1 ?應(yīng)用程序通過recv調(diào)用時。是否在等待數(shù)據(jù)的接收
#define SOCK_NOSPACE 2 ?非異步情況下該套接口的發(fā)送隊(duì)列是否已滿
#define SOCK_PASSCRED 3 ?是否設(shè)置了SOCK_PASSCRED選項(xiàng)
#define SOCK_PASSSEC 4 ?是否設(shè)置了SOCK_PASSSEC

struct fasync_struct *fasync_list

存在了異步通知的隊(duì)列

wait_queue_head_t?wait

等待該套接口的進(jìn)程隊(duì)列

struct file *file

指向了與該套接口綁定的file結(jié)構(gòu)的指針

struct sock?*sk;

與該套接口關(guān)聯(lián)的傳輸控制塊

const struct proto_ops *ops;

用來將套接口層的系統(tǒng)調(diào)用映射到對應(yīng)傳輸層協(xié)議實(shí)現(xiàn)

PF_INET協(xié)議族定義了三種prote_ops結(jié)構(gòu)實(shí)例

TCP ? ? ?inet_stream_ops

UDP ? ? ?inet_dgram_ops

RAW ? ? ?inet_sockraw_ops

proto_ops結(jié)構(gòu)

整個proto_ops結(jié)構(gòu)能夠看作是一張?zhí)捉涌谙到y(tǒng)調(diào)用到傳輸層函數(shù)的跳轉(zhuǎn)表,當(dāng)中的某些操作會繼續(xù)通過proto結(jié)構(gòu)跳轉(zhuǎn)表,進(jìn)入詳細(xì)的傳輸層或網(wǎng)絡(luò)層的處理。

既然proto_ops結(jié)構(gòu)完畢的是從與協(xié)議無關(guān)的套接口層到協(xié)議相關(guān)的傳輸層的轉(zhuǎn)接,而proto結(jié)構(gòu)又將傳輸層映射到網(wǎng)絡(luò)層,那么可想而知每一個傳輸層的協(xié)議都須要定義一個特定的proto_ops實(shí)例和proto實(shí)例。在ipv4協(xié)議族中,一個傳輸層協(xié)議相應(yīng)一個inet_protosw結(jié)構(gòu),inet_protosw結(jié)構(gòu)包括了proto_ops結(jié)構(gòu)和proto結(jié)構(gòu)。


套接口文件系統(tǒng)

每一種文件都有各自的文件類型,如設(shè)備文件包含字符設(shè)備和塊設(shè)備文件等。而與套接口關(guān)聯(lián)的文件類型為套接口文件。

套接口文件系統(tǒng)類型

為了能使套接口與文件描寫敘述符關(guān)聯(lián),并支持特殊套接口層的i節(jié)點(diǎn)的分配和釋放,系統(tǒng)中添加了sockfs文件系統(tǒng)sock_fs_type,通過sockfs文件系統(tǒng)的getsb接口和超級塊操作集合中的alloc_inode和destroy_inode,能夠分配和釋放與套接口文件相關(guān)的i節(jié)點(diǎn)。能夠通過/proc/filesystems文件查看操作系統(tǒng)支持的文件系統(tǒng)。

static const struct super_operations sockfs_ops = {.alloc_inode = sock_alloc_inode,.destroy_inode =sock_destroy_inode,.statfs = simple_statfs, };static int sockfs_get_sb(struct file_system_type *fs_type,int flags, const char *dev_name, void *data,struct vfsmount *mnt) {return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC,mnt); }static struct vfsmount *sock_mnt __read_mostly;static struct file_system_type sock_fs_type = {.name = "sockfs",.get_sb = sockfs_get_sb,.kill_sb = kill_anon_super, };

套接口文件的inode

套接口文件系統(tǒng)的i節(jié)點(diǎn)和套接口是一一相應(yīng)的,因此套接口文件系統(tǒng)的i節(jié)點(diǎn)的分配時比較特殊的。分配的并非一個單純的i節(jié)點(diǎn)。而是i節(jié)點(diǎn)和socket結(jié)構(gòu)的組合體,即socket_alloc結(jié)構(gòu)。這樣能夠使套接口的分配及與之綁定的套接口文件i節(jié)點(diǎn)的分配同一時候進(jìn)行。在應(yīng)用層訪問套接口要通過文件描寫敘述符,這樣能夠高速通過文件描寫敘述符定位與之綁定的套接口。

struct socket_alloc {struct socket socket;struct inode vfs_inode; }; static struct inode *sock_alloc_inode(struct super_block *sb) {struct socket_alloc *ei;ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);if (!ei)return NULL;init_waitqueue_head(&ei->socket.wait);ei->socket.fasync_list = NULL;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; }static void sock_destroy_inode(struct inode *inode) {kmem_cache_free(sock_inode_cachep,container_of(inode, struct socket_alloc, vfs_inode)); }

套接口文件

套接口有一套獨(dú)立的系統(tǒng)調(diào)用。包含建立套接口、連接和IO操作等,因?yàn)樵诮⑻捉涌诤蠓祷氐氖俏募鑼憯⑹龇?#xff0c;因此也能夠通過標(biāo)準(zhǔn)的文件IO操作進(jìn)行對套接口的讀寫,比如用send()進(jìn)行數(shù)據(jù)的發(fā)送,而其實(shí)也能夠通過write系統(tǒng)調(diào)用而達(dá)到相同的效果。這是因?yàn)樵趧?chuàng)建套接口文件時,使file結(jié)構(gòu)中的f_op指向了socket_file_ops。

通過socket_file_ops。能夠看到套接口文件支持那些系統(tǒng)調(diào)用

static const struct file_operations socket_file_ops = {.owner = THIS_MODULE,.llseek = no_llseek,.aio_read = sock_aio_read,.aio_write = sock_aio_write,.poll = sock_poll,.unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT.compat_ioctl = compat_sock_ioctl, #endif.mmap = sock_mmap,.open = sock_no_open, /* special open code to disallow open via /proc */.release = sock_close,.fasync = sock_fasync,.sendpage = sock_sendpage,.splice_write = generic_splice_sendpage,.splice_read = sock_splice_read, };

套接口文件與套接口的綁定

應(yīng)用層是通過文件描寫敘述符來訪問套接口的。因此在調(diào)用socket系統(tǒng)調(diào)用創(chuàng)建套接口時。在創(chuàng)建后會調(diào)用sock_map_fd()綁定套接口和文件描寫敘述符

static int sock_attach_fd(struct socket *sock, struct file *file, int flags) {struct dentry *dentry;struct qstr name = { .name = "" };dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);if (unlikely(!dentry))return -ENOMEM;dentry->d_op = &sockfs_dentry_operations;/** We dont want to push this dentry into global dentry hash table.* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED* This permits a working /proc/$pid/fd/XXX on sockets*/dentry->d_flags &= ~DCACHE_UNHASHED;d_instantiate(dentry, SOCK_INODE(sock));sock->file = file;init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,&socket_file_ops);SOCK_INODE(sock)->i_fop = &socket_file_ops;file->f_flags = O_RDWR | (flags & O_NONBLOCK);file->f_pos = 0;file->private_data = sock;return 0; }int sock_map_fd(struct socket *sock, int flags) {struct file *newfile;int fd = sock_alloc_fd(&newfile, flags);if (likely(fd >= 0)) {int err = sock_attach_fd(sock, newfile, flags);if (unlikely(err < 0)) {put_filp(newfile);put_unused_fd(fd);return err;}fd_install(fd, newfile);}return fd; }

進(jìn)程、文件描寫敘述符和套接口

在task_struct結(jié)構(gòu)中,files指向file_struct結(jié)構(gòu),該結(jié)構(gòu)的主要功能是管理fd_array指針數(shù)組指向的描寫敘述符,每個file結(jié)構(gòu)描寫敘述一個打開的文件。

套接口層的初始化

static int __init sock_init(void) {/** Initialize sock SLAB cache.*/sk_init();/** Initialize skbuff SLAB cache*/skb_init();/** Initialize the protocols module.*/init_inodecache();register_filesystem(&sock_fs_type);sock_mnt = kern_mount(&sock_fs_type);/* The real protocol initialization is performed in later initcalls.*/#ifdef CONFIG_NETFILTERnetfilter_init(); #endifreturn 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/lxjshuju/p/6953033.html

總結(jié)

以上是生活随笔為你收集整理的套接口学习(一)实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。