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. C数据结构排序算法——希尔排序法用法总结(转http://www.cnblogs.com/skywang12345/p/3597597.html)

    希尔排序介绍 希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进.该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 希尔排序实质上是一种分组插入方法.它 ...

  2. 导出excel-文件流

    后台代码(控制器或者dao层) public void Excel(){ //第一步:(1)以虚拟表的形式获取导出数据 DataTable dt_0 = this.service.Excel(); / ...

  3. C# 面向对象1(类和对象的概念)

    1.面向过程-->面向对象 面向过程:面向的是完成这件事儿的过程,强调的是完成这件事儿的动作. 2.面向过程的思想: 以上的,需求一更改,会导致不同的方法,一一去更改. 3.面向对象的思想:找个 ...

  4. 提升scrapy的爬取效率

    增加并发: 默认scrapy开启的并发线程为32个,可以适当进行增加.在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100. 降低日志级别 ...

  5. java实现spark常用算子之flatmap

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.a ...

  6. PostMan测试Web Service

    1.设置URL 2.设置请求模式:Post 3.设置Header:添加 Content-Type ,值为 text/xml;charset=utf-8 4.设置Body:勾选raw 5.输入Body内 ...

  7. CVE-2018-0802漏洞利用

    看了一天apt报告,主流利用Office鱼叉攻击的漏洞,还是这Microsoft Office CVE-2017-8570,CVE-2017-11882和CVE-2018-0802 三个,而且都知道o ...

  8. ASP.NET Core WebAPI帮助页--Swagger简单使用1.0

    1.什么是Swagger? Swagger是一个规范且完整的框架,提供描述.生产.消费和可视化RESTful API,它是为了解决Web API生成有用文档和帮助页的问题.   2.为啥选用swagg ...

  9. 安装Maatwebsite \ EXCEL \ ExcelServiceProvider

    安装时报错 composer You can also run `php --ini` inside terminal to see which files are used by PHP in CL ...

  10. 如何在 Ubuntu 上安装 pip

    1.为 Python 2 安装 pip 首先,确保已经安装了 Python 2. 在 Ubuntu 上,可以使用以下命令进行验证 python2 --version 如果没有错误并且显示了 Pytho ...