server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建socket时,会发起系统调用,调用内核的sys_socketcall
函数
|
|
根据信号选择不同函数处理,创建sockcet会发出SYS_SOCKET
信号,从而由sys_socket
处理
|
|
主要做两件事
sock_create
, 生成一个socketsock_map_fd
, 生成一个fd跟这个socket绑定, 使socket能通过fd进行访问
sock_create 创建socket, 传入的 struct socket *sock
, 这个socket 结构体就是我们socket 的数据结构。具体创建过程我们这里不做详细展开。
|
|
主要看一下sock_map_fd
|
|
重点看下 get_unused_fd
|
|
get_unused_fd
主要从小开始找到第一个可用的fd,然后标记为忙(不可被用来标识其他文件)。
可以看到是从 fdt->open_fds->fds_bits
来找第一个可用fd,并且找到后要把 FD_SET(fd, fdt->open_fds);
标记为已分配。
从fdt的结构体里看到
|
|
open_fds
数据类型是 fd_set
|
|
我们可以看出open_fds->fds_bits
是一个数组,长度为__FDSET_LONGS
数组中每个元素有 sizeof(unsigned long)*8 个比特位,fds_bits一共有 1024个比特位。这种用bit来存储数据的方式成为bitmap(具体介绍可以参看这里),好处是可以大大节省存储空间。
|
|
用图表说明一下分配一个fd过程 get_unused_fd
- 获得
fdt = files_fdtable(files);
- 从fdt->open_fds里找第一个为0的标志位,这里0号,1号,2号,默认分配给了标准输入、标准输出和标准错误。
- 找到第三个比特位是0,分配一个fd为3出来
- 把第三个比特位设置为1,表明已经被分配了
FD_SET(fd, fdt->open_fds);
fdt->next=fd+1
fdt->next变为4,则下一次分配的时候从fdt->next 第四个比特位开始找起。
知道了在创建时如何分配fd,再看一下socket close时如何回收fd
同样地socket在关闭时也会发起系统调用
|
|
跟上面分配fd 对应的是释放fd的操作
__put_unused_fd
|
|
- 会把释放的fd对应的fdt->open_fds标志位重新置为0。
- fdt->next指向当前fd对应的标志位。
这样也就解释了上文中为fd=4的文件描述符会被不断利用的原因。