socket函数的domain、type、protocol解析
lxg@2015-04-09
-
内核中的socket概览
图一:socket概览
内核中套接字是一层一层进行抽象展示的,把共性的东西抽取出来,这样对外提供的接口可以尽量的统一。内核中把套接字的定义会抽象出来展示,如struct sock->struct inet_sock->struct tcp_sock从抽象到具体。还会把套接字的操作也会抽象,下面我们会提到怎么进行抽象展示的。
Socket函数中的三个参数其实就是把抽象的socket具体化的条件,domain参数决定了图中所示的第二层通信域,type决定了第三层的通信模式,protocol决定了第四层真正的通信协议。
-
Domain参数
Domain参数指定了通信的”域”(在后文中会用family替代domain),我们是在IPv4还是IPv6这个范围内通信,也就决定了我们通信的地址是IPv4格式还是IPv6格式。通常可选的定义如下:
名称 |
目的 |
AF_UNIX, AF_LOCAL |
本地通信 |
AF_INET |
IPv4网络通信 |
AF_INET6 |
IPv6网络通信 |
AF_PACKET |
链路层通信 |
在Linux系统中AF_*和PF_*是等价的。
在内核源码中net目录下面有Af_开头的一系列文件(如:Af_inet.c、Af_inet6.c、Af_unix.c等),每一个文件分别代表了一种协议族。
在Net.h中定义了一个结构体:
//net_proto_family结构体定义了每一个协议族的新建socket句柄 struct net_proto_family { int family; int (*create)(struct net *net, struct socket *sock, int protocol, int kern); struct module *owner; }; //Af_inet.c中的PF_INET domain的定义 static const struct net_proto_family inet_family_ops = { .family = PF_INET, .create = inet_create, .owner = THIS_MODULE, }; |
在协议栈初始化的通过sock_register(const struct net_proto_family *ops)(socket.c)函数把协议栈支持的协议族family加入net_families数组中。
当我们通过socket系统调用创建套接字的时候流程走到__sock_create函数(SYSCALL_DEFINE3->sock_create->__sock_create)的时候根据family在net_families数组中取得对应协议族的create句柄,所以对于PF_INET协议族的套接字就是调用inet_create来新建socket。
通过上面分析可知family这个参数决定了调用哪个协议族create函数来新建socket,说得可能不准确点就是决定了你使用net/目录下面的哪个Af_*.c文件中的函数。
-
Type参数
Type就是socket的类型,对于AF_INET协议族而言有流套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)。
/** * enum sock_type - Socket types * @SOCK_STREAM: stream (connection) socket * @SOCK_DGRAM: datagram (conn.less) socket * @SOCK_RAW: raw socket * @SOCK_RDM: reliably-delivered message * @SOCK_SEQPACKET: sequential packet socket * @SOCK_DCCP: Datagram Congestion Control Protocol socket * @SOCK_PACKET: linux specific way of getting packets at the dev level. * For writing rarp and other similar things on the user level. */ enum sock_type { |