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. java 给定一个日期期间 返回形如Mar 2015 3/20-3/31的数据

    最近一个项目中有个前台对于表头要求: 给定一个日期期间返回形如 Mar 2015 3/20-3/31Apr 2015 4/1-4/30 这样的月年数据,简单的写了下代码,暂时没想到更好的办法 例如传进 ...

  2. CentOS7部署HDP3.1.0.0

    Apache Ambari是一个基于Web的支持Apache Hadoop集群的供应.管理和监控的开源工具,Ambari已支持大多数Hadoop组件,包括HDFS.MapReduce.Hive.Pig ...

  3. N1试卷常考词汇总结

    免れる まぬがれる 免去,幸免 軽率 けいそつ 轻率,草率 捩れる ねじれる 拧劲儿,扭歪,弯曲 裂ける さける 裂开,破裂 避ける さける 躲避,避开 つまむ 挟,捏,掐 追及 ついきゅう 追上.追 ...

  4. Java定义队结构,实现入队、出队操作

    package com.example.demo; import java.util.ArrayList; public class Queue { ArrayList<Object> l ...

  5. Jdk1.8的安装(Linux和windows)

    1.1 JDK1.8下载地址 JDK下载:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151. ...

  6. Linux添加虚拟网卡的多种方法

    Linux添加虚拟网卡的多种方法有时候,一台服务器需要设置多个ip,但又不想添加多块网卡,那就需要设置虚拟网卡.这里介绍几种方式在linux服务器上添加虚拟网卡. 我们向eth0中添加一块虚拟网卡: ...

  7. conda 安装虚拟环境 fastai

    一.conda常用命令 1.创建一个虚拟环境env_name,后面跟的是创建这个环境时,同时安装的软件包 conda create -n env_name python=3.6 2.通过克隆创建一个环 ...

  8. [uboot] (番外篇)uboot之fdt介绍 (转)

    以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例 [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(B ...

  9. 轮子:读取config.ini文件

    python: 把config.ini文件成map返回 def get_conf(conf_file): conf = {} ll=list(map(lambda x: x.replace('&quo ...

  10. WSL中使用npm install报错

    报错内容类似下面的格式.具体解决方法请看这里:https://github.com/Microsoft/WSL/issues/14 着重关注 https://github.com/Microsoft/ ...