close系统调用用于关闭文件描述符,其系统调用实现如下所示;

 /
* Careful here! We test whether the file pointer is NULL before
* releasing the fd. This ensures that one clone task can't release
* an fd while another clone is opening it.
*/
SYSCALL_DEFINE1(close, unsigned int, fd)
{
int retval = __close_fd(current->files, fd); /* can't restart close syscall because file table entry was cleared */
if (unlikely(retval == -ERESTARTSYS ||
retval == -ERESTARTNOINTR ||
retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK))
retval = -EINTR; return retval;
}
EXPORT_SYMBOL(sys_close);

本文重点在于分析套接字的的close部分,所以简要列出close系统调用通用流程的函数调用关系,如下;

补充:其中重点注意下fput函数,该函数会先现将文件的引用计数-1,然后判断是否为0,为0的时候才会进行继续的流程,也就是说当socket存在多个引用的时候,只有最后一个close才会触发后面的调度销毁流程,也是close与shutdown不同的一个地方;

 /**
* close系统调用函数调用关系
*__close_fd
* |-->filp_close
* |-->fput 将file加入到delayed_fput_list链表
* |-->schedule_delayed_work 调度延迟执行队列处理链表
* |-->delayed_fput
* |-->__fput
* |-->file->f_op->release 调用文件的release操作
*/

可见,在close系统调用中会调用文件的release操作,所以我们本文重点分析socket的release操作实现;

socket实现的文件操作结构如下所示,其中本文讨论的release函数实现为sock_close;

 /* socket文件操作函数 */
static const struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read_iter = sock_read_iter,
.write_iter = sock_write_iter,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_sock_ioctl,
#endif
.mmap = sock_mmap,
.release = sock_close,
.fasync = sock_fasync,
.sendpage = sock_sendpage,
.splice_write = generic_splice_sendpage,
.splice_read = sock_splice_read,
};

在socket_release函数中,会调用socket操作函数release,ipv4对应inet_release;

 /* 关闭socket */
static int sock_close(struct inode *inode, struct file *filp)
{
/* socket关闭 */
sock_release(SOCKET_I(inode));
return ;
}
 /**
* sock_release - close a socket
* @sock: socket to close
*
* The socket is released from the protocol stack if it has a release
* callback, and the inode is then released if the socket is bound to
* an inode not a file.
*/ void sock_release(struct socket *sock)
{
if (sock->ops) {
struct module *owner = sock->ops->owner; /* 调用socket操作中的release */
sock->ops->release(sock);
sock->ops = NULL;
module_put(owner);
} if (rcu_dereference_protected(sock->wq, )->fasync_list)
pr_err("%s: fasync list not empty!\n", __func__); /* 减少cpu的套接口数量 */
this_cpu_sub(sockets_in_use, ); /* 容错处理 */
if (!sock->file) {
iput(SOCK_INODE(sock));
return;
} /* 套接口完成关闭,继续执行close系统调用其他流程 */
sock->file = NULL;
}

inet_release负责退出组播组,根据是否开启linger标记来设置延迟关闭时间,并且调用传输层的close函数,对于tcp来说,其调用的为tcp_close;

 /*
* The peer socket should always be NULL (or else). When we call this
* function we are destroying the object and from then on nobody
* should refer to it.
*/
int inet_release(struct socket *sock)
{
struct sock *sk = sock->sk; if (sk) {
long timeout; /* Applications forget to leave groups before exiting */
/* 退出组播组 */
ip_mc_drop_socket(sk); /* If linger is set, we don't return until the close
* is complete. Otherwise we return immediately. The
* actually closing is done the same either way.
*
* If the close is due to the process exiting, we never
* linger..
*/
timeout = ; /*
设置了linger标记,进程未在退出,
则设置lingertime延迟关闭时间
*/
if (sock_flag(sk, SOCK_LINGER) &&
!(current->flags & PF_EXITING))
timeout = sk->sk_lingertime;
sock->sk = NULL; /* 调用传输层的close函数 */
sk->sk_prot->close(sk, timeout);
}
return ;
}

tcp_close分析请移步另外一篇文章<TCP层close系统调用的实现分析>;

套接字之close系统调用的更多相关文章

  1. 套接字之recv系统调用

    recv系统调用对sys_recvfrom进行了简单的封装,只是其中不包含地址信息,其只需要从建立连接的另一端接收信息: /* * Receive a datagram from a socket. ...

  2. 套接字之send系统调用

    send系统调用只是对sendto系统调用进行了封装,传递的参数不包含目的地址信息,数据会发送到已经建立连接的另一端的地址: /* * Send a datagram down a socket. * ...

  3. 套接字之recvmsg系统调用

    recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息:接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收: SYS ...

  4. 套接字之recvfrom系统调用

    recvfrom系统调用通过用户传入的接收空间构造msghdr,并且调用sock_recvmsg,该函数调用socket操作的recvmsg函数sock->ops->recvmsg,ipv ...

  5. 套接字之sendmsg系统调用

    sendmsg系统调用允许在用户空间构造消息头和控制信息,用此函数可以发送多个数据缓冲区的数据,并支持控制信息:当调用进入内核后,会将用户端的user_msghdr对应拷贝到内核的msghdr中,然后 ...

  6. 套接字之sendto系统调用

    sendto系统调用用于向指定的目的地址发送数据,其系统调用的流程比较容易理解,如下面所示,其主要完成 (1)将用户数据组织成msghdr,(2)而后调用socket操作的sendmsg:ipv4对应 ...

  7. 套接字之select系统调用

    select是IO多路复用的一种方式,用来等待一个列表中的多个描述符的可读可写状态: SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_ ...

  8. 【 Linux 】Linux套接字简要说明

    Linux套接字    源IP地址和目的IP地址以及源端口和目标端口号的组合称为套接字.其作用于标识客户端请求的服务器和服务. 套接字,支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间 ...

  9. 1、套按字及http基础知识之一

    MAC地址:设备到设备之间通信时专用(从源主机到目标主机可能经由N台路由设备)4 IP地址:标记主机到主机之间通信时专用 TCP/UDP :提供进程地址 通过port number来标记 进程地址:用 ...

随机推荐

  1. EBS自动行号,行金额自动汇总到头,金额根据币种编号总结

    一.自动行号实现 1.方法一: 只需要将“序号”定义成公式,并将公式设置为:get_block_property('block_name',current_record)就可以实现了,或者把这行语句放 ...

  2. 预约系统(二) MVC框架搭建

    采用VS2013,自带的MVC4来搭建 MODEL层,表对象的建立: T_Bm.cs using System; using System.Collections.Generic; using Sys ...

  3. ccs之经典布局(一)(水平垂直居中)

    经典的css布局有以下几种,下面分别用不同的方法进行实现且进行对比. 一.水平居中 水平居中布局指的是当前元素在父级元素的容器中,水平方向上显示的是居中的,有以下几种方式来完成布局: 1.margin ...

  4. redis性能指标

    1.当内存使用达到设置的最大阀值时,需要选择一种key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”属性值. 若是Redis数据集中的key都设置了过期时间,那 ...

  5. ISO/IEC 15444-12 MP4 封装格式标准摘录 2

    目录 Track Media Structure Media Box Media Header Box Handler Reference Box Media Information Box Medi ...

  6. dumpe2fs Linux支持的文件系统

    dumpe2fs  (-bh)装置文件名 选项与参数: -b : 列出保留为坏轨的部分 -h : 仅列出superblock的数据,不会列出其他的区段内容 查看Linux支持的文件系统哪些支持: ls ...

  7. Django学习系列12:把Python变量传入模板中渲染

    从视图的Python代码中把变量传入HTML模板. 模板中使用哪种句法引入Python对象,要使用的符号{{...}},它会以字符串的形式显示对象: <html> <head> ...

  8. 从头开始 — CSS — 垂直居中

    事实上,每次面试前端必问的问题就是这个.及其常见的需求,看起来似乎非常简单,但是实现起来很费劲,尤其是涉及尺寸不固定的元素. 本篇文章将介绍比较流行的几种方法. 行内块 <body> &l ...

  9. mybatis 分页插件PageHelper的简单使用

    首先在pom.xml配置文件中增加相关的插件. 插件地址:https://github.com/pagehelper/Mybatis-PageHelper <dependency> < ...

  10. 处理并解决mysql8.0 caching-sha2-password问题,开启远程访问

    原文:https://blog.csdn.net/u010026255/article/details/80062153 启动mysql服务:service mysqld start ALTER US ...