socket函数原型:

/* Create a new socket of type TYPE in domain DOMAIN, using
protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
Returns a file descriptor for the new socket, or -1 for errors. */
extern int socket (int __domain, int __type, int __protocol) __THROW;

socket函数原型:

/* Create a new socket of type TYPE in domain DOMAIN, using
protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
Returns a file descriptor for the new socket, or -1 for errors. */
extern int socket (int __domain, int __type, int __protocol) __THROW;

参数一:协议族信息可选字段

AF_INET   IPv4网络协议中采用的地址族
AF_INET6  IPv6网络协议中采用的地址族
AF_LOCAL  本地通信中采用的UNIX协议的地址族

参数二:套接字类型

SOCKET_RAW   原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IP、 ICMP协议
SOCK_STREAM  SOCK_STREAM是数据流,一般为TCP/IP协议的编程
SOCK_DGRAM   SOCK_DGRAM是数据报,一般为UDP协议的网络编程

参数三:最终采用的协议

传输协议 IPPROTO_TCP 和 IPPTOTO_UDP,一般默认为0(由系统自动选择)

 

socket的返回值是一个描述符,它具有其他Unix描述符的所有特性:可以用这个描述符调用read和write;可以用dup复制它,在调用了fork后,父进程和子进程可以共享它;可以调用fcntl来改变它的属性,可以调用close来关闭它,等等。插口描述符是sendtorecvfrom等函数的第一个参数,也是进行通信所不可或缺的。当程序终止时 (通过调用exit),所有打开的描述符,包括插口描述符都会被内核关闭。

进程调用socket时,内核会创建一些数据结构。首先从进程的进程表表项开始。在每个进程的生存期内都会有一个对应的进程表表项存在。

看下图:

 

 

 

proc{ } 在此代表进程表项,在这个结构中的项p_fd 指向进程的filedesc结构。其中有两个我们现在关心的成员:一个是 fd_ofileflags ,它是一个字符数组指针 (每个描述符有一个描述符标志,此处不做过多介绍 );一个是fd_ofiles,它是一个指向文件表结构的指针数组的指针 。fd_ofiles指向的数据结构用*file{ } [ ]来表示。它是一个指向file结构的指针数组。这个数组及描述符标志数组的下标就是描述符本身: 012(分别对应着标准输入、标准输出、标准错误,是由系统默认打开的三个描述符)等等,是非负整数。在上图中可以看到描述符 012对应的项指向图底部的同一个 f i l e结构(由于这三个描述符都对应终端设备)。描述符3对应的项指向另外一个 f i l e结构,是我们感兴趣的socket结构和它所指向的Internet专用数据结构。

结构file的成员f_type指示描述符的类型是DTYPE_SOCKET和DTYPE_VNODE。 v-node是一个通用机制,允许内核支持不同类型的文件系统—磁盘文件系统、网络文件系统(如NFS )、CD-ROM文件系统、基于存储器的文件系统等等,TCP/IP插口的类型总是DTYPE_SOCKET。

结构f i l e的成员f _ d a t a指向一个s o c k e t结构或者一个v n o d e结构,根据描述符类型而定。成员f _ o p s指向一个有 5个函数指针的向量。这些函数指针用在 r e a dr e a d vw r i t ew r i t e vi o c t ls e l e c tc l o s e系统调用中,这些系统调用需要一个插口描述符或非插口描述符。这些系统调用每次被调用时都要查看f _ t y p e的值, 然后做出相应的跳转,实现者选择了直接通过f i l e o p s结构的相应项来跳转的方式。

当描述符的类型是DTYPE_SOCKET时,结构file指向结构socket。在我们的例子中,socket的类型(数据报插口的类型是SOCK_DGRAM)保存在成员so_type中。还分配了一个Internet协议控制块(PCB):一个inpcb结构。结构socket的成员so_pcb指向inpcb,并且结构inpcb的成员inp_socket指向结构socket。对于一个给定插口的操作可能来自两个方向:“上”或“下”,因此需要有指针来互相指向。

1)当进程执行一个系统调用时,如sendto,内核从描述符值开始,使用fd_ofiles索引到file结构指针向量,直到描述符所对应的file结构。结构file指向socket结构,结构socket带有指向结构inpcb的指针。
2)当一个UDP数据报到达一个网络接口时,内核搜索所有UDP协议控制块,寻找一个合适的,至少要根据目标UDP端口号,可能还要根据目标IP地址、源IP地址和源端口号。一旦定位所找的inpcb,内核就能通过inp_socket指针来找到相应的socket结构。
成员inp_faddr和inp_laddr包含远地和本地IP地址,而成员inp_fport和inp_lport包含远地和本地端口号。IP地址和端口号的组合经常叫做一个插口。至此,我们申请到了最小的可用文件描述符,并且内核已经创建了相应的用来通信的数据结构,接下来进程将通过bind、listen、accept等系统调用来配置系统,完成通信。

 

版权声明:本文为klxs1996原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/klxs1996/p/12748576.html