套接口学习(一)实现
? 套接口這個概念最先由4.2BSD(1983)引入。如今已經成為一個通用的網絡應用程序編程接口。受到全部操作系統的支持。套接口層位于應用程序和 協議棧之間,相應用程序屏蔽了與協議相關實現的詳細細節。
? 通常,應用程序中調用庫函數。而庫函數通過系統調用進入套接口層,Linux的套接口層實現提供了一組專門的套接口系統調用。分別在相應的庫函數名之上加上"sys_"前綴。此外為了體現一切皆文件的理念。Linux也同意標準I/O系統調用通過一個套接口文件描寫敘述符來讀寫其相應套接口上的網絡連接。就像通過文件描寫敘述符訪問一個已經打開的普通文件一樣。
套接口在創建時。即與一個文件及一個文件描寫敘述符綁定,此后全部對該套接口的操作都是通過與其綁定的文件描寫敘述符進行的,包含專門的套接口系統調用。頁包含標準的I/O系統調用對套接口的操作,與套接口綁定的文件類型為套接口文件。
套接口層的調用涉及下面文件:
include/linux/net.h ?定義套接口層相關的結構、宏和函數原型
include/net/sock.h ? 定義主要的傳輸控制塊結構、宏和函數原型
net/socket.c ?實現套接口層的系統調用
net/ipv4/af_inet.c 網絡層和傳輸層接口
socket結構
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
用于表示所在套接口所處的狀態標志。該標志有些狀態僅僅對TCP套接口有意義,由于僅僅有TCP是面向連接的協議
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, 基于數據報的套接口
SOCK_RAW = 3, 原始套接口
SOCK_RDM = 4, 可靠傳送報文套接口
SOCK_SEQPACKET = 5, 順序分組套接口
SOCK_DCCP = 6, 數據報擁塞控制協議套接口
SOCK_PACKET = 10,混雜模式套接口
};
flags
一組標志位
#define SOCK_ASYNC_NOSPACE 0 ?該套接口發送隊列是否已滿
#define SOCK_ASYNC_WAITDATA 1 ?應用程序通過recv調用時。是否在等待數據的接收
#define SOCK_NOSPACE 2 ?非異步情況下該套接口的發送隊列是否已滿
#define SOCK_PASSCRED 3 ?是否設置了SOCK_PASSCRED選項
#define SOCK_PASSSEC 4 ?是否設置了SOCK_PASSSEC
struct fasync_struct *fasync_list
存在了異步通知的隊列
wait_queue_head_t?wait
等待該套接口的進程隊列
struct file *file
指向了與該套接口綁定的file結構的指針
struct sock?*sk;
與該套接口關聯的傳輸控制塊
const struct proto_ops *ops;
用來將套接口層的系統調用映射到對應傳輸層協議實現
PF_INET協議族定義了三種prote_ops結構實例
TCP ? ? ?inet_stream_ops
UDP ? ? ?inet_dgram_ops
RAW ? ? ?inet_sockraw_ops
proto_ops結構
整個proto_ops結構能夠看作是一張套接口系統調用到傳輸層函數的跳轉表,當中的某些操作會繼續通過proto結構跳轉表,進入詳細的傳輸層或網絡層的處理。
既然proto_ops結構完畢的是從與協議無關的套接口層到協議相關的傳輸層的轉接,而proto結構又將傳輸層映射到網絡層,那么可想而知每一個傳輸層的協議都須要定義一個特定的proto_ops實例和proto實例。在ipv4協議族中,一個傳輸層協議相應一個inet_protosw結構,inet_protosw結構包括了proto_ops結構和proto結構。
套接口文件系統
每一種文件都有各自的文件類型,如設備文件包含字符設備和塊設備文件等。而與套接口關聯的文件類型為套接口文件。
套接口文件系統類型
為了能使套接口與文件描寫敘述符關聯,并支持特殊套接口層的i節點的分配和釋放,系統中添加了sockfs文件系統sock_fs_type,通過sockfs文件系統的getsb接口和超級塊操作集合中的alloc_inode和destroy_inode,能夠分配和釋放與套接口文件相關的i節點。能夠通過/proc/filesystems文件查看操作系統支持的文件系統。
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
套接口文件系統的i節點和套接口是一一相應的,因此套接口文件系統的i節點的分配時比較特殊的。分配的并非一個單純的i節點。而是i節點和socket結構的組合體,即socket_alloc結構。這樣能夠使套接口的分配及與之綁定的套接口文件i節點的分配同一時候進行。在應用層訪問套接口要通過文件描寫敘述符,這樣能夠高速通過文件描寫敘述符定位與之綁定的套接口。
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)); }
套接口文件
套接口有一套獨立的系統調用。包含建立套接口、連接和IO操作等,因為在建立套接口后返回的是文件描寫敘述符,因此也能夠通過標準的文件IO操作進行對套接口的讀寫,比如用send()進行數據的發送,而其實也能夠通過write系統調用而達到相同的效果。這是因為在創建套接口文件時,使file結構中的f_op指向了socket_file_ops。
通過socket_file_ops。能夠看到套接口文件支持那些系統調用
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, };
套接口文件與套接口的綁定
應用層是通過文件描寫敘述符來訪問套接口的。因此在調用socket系統調用創建套接口時。在創建后會調用sock_map_fd()綁定套接口和文件描寫敘述符
進程、文件描寫敘述符和套接口
在task_struct結構中,files指向file_struct結構,該結構的主要功能是管理fd_array指針數組指向的描寫敘述符,每個file結構描寫敘述一個打開的文件。
套接口層的初始化
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; }
轉載于:https://www.cnblogs.com/lxjshuju/p/6953033.html
總結
以上是生活随笔為你收集整理的套接口学习(一)实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zbb20170606 oracle 查
- 下一篇: web的几种轮播