套接字socket 的地址族和类型、工作原理、创建过程
注:本分类下文章大多整理自《深入分析linux内核源代码》一书,另有参考其他一些资料如《linux内核完全剖析》、《linux c 编程一站式学习》等,只是为了更好地理清系统编程和网络编程中的一些概念性问题,并没有深入地阅读分析源码,我也是草草翻过这本书,请有兴趣的朋友自己参考相关资料。此书出版较早,分析的版本为2.4.16,故出现的一些概念可能跟最新版本内核不同。
此书已经开源,阅读地址 http://www.kerneltravel.net
.png)
读取,使得我们对网络的控制和对文件的控制一样方便。
种类拥有自己的通信寻址方法。Linux 所支持的套接字地址族见表12.3。
Linux 将上述套接字地址族抽象为统一的 BSD 套接字接口,应用程序关心的只是 BSD 套
接字接口,而 BSD 套接字由各地址族专有的软件支持。一般而言,BSD 套接字可支持多种套
接字类型,不同的套接字类型提供的服务不同,Linux 所支持的部分 BSD 套接字类型见表
12.4,但表12.3 中的套接字地址族并不一定全部支持表12.4 中的这些套接字类型。
.png)
如图12.8 所示,这里也体现了Linux 网络模块分层的设计思想。
.png)
实际是一组协议的操作例程,在include/linux/net.h 中定义为struct proto_ops:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
struct proto_ops
{ int family; int (*release) ( struct socket *sock); int (*bind) ( struct socket *sock, struct sockaddr *umyaddr, int sockaddr_len); int (*connect) ( struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags); int (*socketpair) ( struct socket *sock1, struct socket *sock2); int (*accept) ( struct socket *sock, struct socket *newsock, int flags); int (*getname) ( struct socket *sock, struct sockaddr *uaddr, int *usockaddr_len, int peer); unsigned int (*poll) ( struct file *file, struct socket *sock, struct poll_table_struct *wait); int (*ioctl) ( struct socket *sock, unsigned int cmd, unsigned long arg); int (*listen) ( struct socket *sock, int len); int (*shutdown) ( struct socket *sock, int flags); int (*setsockopt) ( struct socket *sock, int level, int optname, char *optval, int optlen); int (*getsockopt) ( struct socket *sock, int level, int optname, char *optval, int *optlen); int (*sendmsg) ( struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) ( struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); int (*mmap) ( struct file *file, struct socket *sock, struct vm_area_struct *vma); ssize_t (*sendpage) ( struct socket *sock, struct page *page, int offset, size_t size, int flags); }; |
proto_ops 结构中的相应函数执行任务。BSD 套接字层向 INET 套接字层传递 socket 数据
结构来代表一个 BSD 套接字,socket 结构在include/linux/net.h 中定义如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
struct socket
{ socket_state state; unsigned long flags; struct proto_ops *ops; struct inode *inode; struct fasync_struct *fasync_list; /* Asynchronous wake up list */ struct file *file; /* File back pointer for gc */ struct sock *sk; wait_queue_head_t wait; short type; unsigned char passcred; }; |
结构之间存在着链接关系,sock 结构定义于include/net/sock.h
。在 BSD 的 socket 数据结构中存在一个指向sock 的指针sk,而在sock 中又
有一个指向socket 的指针,这两个指针将 BSD socket 数据结构和sock 数据结构链接了起
来。通过这种链接关系,套接字调用就可以方便地检索到 sock 数据结构。实际上,sock 数
据结构可适用于不同的协议,它也定义有自己的协议操作集proto_ops。在建立套接字时,sock
数据结构的协议操作集指针指向所请求的协议操作集。如果请求 TCP,则 sock 数据结构的
协议操作集指针将指向 TCP 的协议操作集。
方式、采用的协议等的不同。Linux 利用 BSD 套接字层抽象了不同的套接字接口。在内核的
初始化阶段,内建于内核的不同地址族分别以 BSD 套接字接口在内核中注册。然后,随着应
用程序创建并使用 BSD 套接字。
内核负责在 BSD 套接字和底层的地址族之间建立联系。这种联系通过交叉链接数据结
构以及地址族专有的支持例程表建立。
在内核中, 地址族和协议信息保存在inet_protos 向量中, 其定义于
include/net/protocol.h:
1
2 3 4 5 6 7 8 9 10 11 12 |
struct inet_protocol *inet_protos[MAX_INET_PROTOS];
/* This is used to register protocols. */ struct inet_protocol { int (*handler)( struct sk_buff *skb); //The Linux kernel uses an sk_buff data structure to describe each packet. void (*err_handler)( struct sk_buff *skb, u32 info); struct inet_protocol *next; unsigned char protocol; unsigned char copy: ; void *data; const char *name; }; |
时,内核调用每个地址族的初始化例程,这时,每个地址族注册自己的协议操作集。协议操
作集实际是一个例程集合,其中每个例程执行一个特定的操作。
套接字类型以及协议,其函数定义于net/socket.c 中:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
asmlinkage
long sys_socket( int family, int type, int protocol) { int retval; struct socket *sock; retval = sock_create(family, type, protocol, &sock); if (retval < ) goto out; retval = sock_map_fd(sock); if (retval < ) goto out_release; out: /* It may be already another descriptor 8) Not kernel problem. */ return retval; out_release: sock_release(sock); return retval; } |
种特殊的文件类型,形成一种特殊的文件系统sockfs,其定义于net/socket.c:
1
2 3 |
static
struct vfsmount *sock_mnt; static DECLARE_FSTYPE(sock_fs_type, "sockfs", sockfs_read_super, FS_NOMOUNT); |
vfsmount 数据结构,这个结构的地址就保存在一个全局的指针sock_mnt 中。所谓创建一个
套接字,就是在
sockfs
文件系统中创建一个特殊文件,或者说一个节点,并建立起为实现套
接字功能所需的一整套数据结构。所以,函数sock_create()首先是建立一个socket 数据结
构,然后将其“映射”到一个已打开的文件中,进行socket 结构和sock 结构的分配和初始
化。
实际就是 proto_ops 数据结构的地址。
核利用 proto_ops 数据结构中的信息调用地址族专有的创建例程。
之后,内核从当前进程的 fd 向量中分配空闲的文件描述符,该描述符指向的 file 数
据结构被初始化。初始化过程包括将文件操作集指针指向由 BSD 套接字接口支持的 BSD 文
件操作集。所有随后的套接字(文件)操作都将定向到该套接字接口,而套接字接口则会进
一步调用地址族的操作例程,从而将操作传递到底层地址族,如图12.10 所示。
程和系统调用界面的,那么sock 结构就是面向底层驱动程序的。可是,为什么不把这两个数
据结构合并成一个呢?
我们说套接字是一种特殊的文件系统,因此,inode 结构内部的union 的一个成分就用
作socket 结构,其定义如下:
1
2 3 4 5 6 7 8 |
struct inode {
....... union { ........ struct socket socket_i; } } |
.png)
分全都放在socket 结构中,则inode 结构中的这个union 就会变得很大,从而inode 结构也
会变得很大,而对于其他文件系统,这个union 成分并不需要那么庞大。因此,就把套接字
所需的这些结构成分拆成两部分,把与文件系统关系比较密切的那一部分放在socket 结构
中,把与通信关系比较密切的那一部分则单独组成一个数据结构,即sock 结构。由于这两部
分数据在逻辑上本来就是一体的,所以要通过指针互相指向对方,形成一对一的关系。
套接字socket 的地址族和类型、工作原理、创建过程的更多相关文章
- Java网络编程--套接字Socket
一.套接字Socket IP地址标志Internet上的计算机,端口号标志正在计算机上运行的进程(程序). 端口号被规定为一个16位的0--65535之间的整数,其中,0--1023被预先定义的服务通 ...
- 套接字编程,创建套接字socket
1.套接字地址结构: struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; 其中,成员sa_family表示套接字的协议族类型,对 ...
- 网络编程(二)--TCP协议、基于tcp协议的套接字socket
一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...
- 网络编程(二)——TCP协议、基于tcp协议的套接字socket
TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...
- 网络编程 套接字socket TCP UDP
网络编程与套接字 网络编程 网络编程是什么: 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...
- Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()
前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...
- [置顶] Java套接字Socket编程
1)概念 网络编程基本模型就客户端到服务器的模型,也就是我们常见的C/S模型.简单的说就是两个进程间相互通信的过程.即通信双方一方作为服务器等待客户端提出请求并给以回应,另一方作为客户端向服务器提出请 ...
- 什么是套接字(Socket)
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据.为了区别不同的应用程序进程和连 ...
- Java套接字Socket编程--TCP参数
在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...
随机推荐
- Scala中的apply实战详解
apply可以应用与Object和Class,单调用情景不一样. 通过Array(1,2,3,4,5) 可以调用到Array中的.appy方法.你可以看源码是如何实现apply的. 类中的appy比较 ...
- 初识Sencha Touch:面板Panel
HTML代码: <!doctype html> <html> <head> <meta charset="utf-8"> <t ...
- c/c++:内存泄露和野指针的概念
内存泄漏 用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.即所谓内存泄漏. 注意:内存泄漏是指堆内存的泄漏. 简单的说就是申请了一块内存空间,使用 ...
- python进阶--文件读写操作
Python读写文件 1. open 使用open打开文件后一定要记得调用 文件对象的close()方法.比如可以用try --finally语句来确保最后能关闭文件. >>>f1 ...
- 如何解决”无法将类型为“System.DateTime”的对象强制转换为类型“System.String”。“
字段Time在数据库中为datetime类型 dr.GetString(3).ToString() dr.GetString(3).ToString() => dr.GetDateTime(3) ...
- 【Win7激活工具2013版下载】适用于旗舰版、家庭高级版等所有版本32/64位 OEM激活
虽然现在Win8已经发布了,但是身边总是还有一些朋友在用着Win7系统,而近期微软频繁的推送补丁包,导致之前的那些激活都失效了.找了网络上很多工具,之前的那些有的已经不能用了,激活不了,今天就推荐一些 ...
- 自定义UITextField(UITextField重写)
// CustomField.h #import <UIKit/UIKit.h> @interface CustomField : UITextField @end // CustomFi ...
- linux内核源码阅读之facebook硬盘加速flashcache之八
前面我们的分析中重点关注正常的数据流程,这一小节关注如果有异常,那么流程是怎么走完的呢? 1)创建新任务时kcached_job申请不到 2)读写命中时cache块为忙 3)系统关机时处理,系统开机时 ...
- Matrix(多线程dp)
Matrix Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- c# 柱状图(转载)
// c# 显示柱状图 using System; using System.Data; using System.Configuration; using System.Web; using Sys ...