从别人那里看,一边翻源码。总结的socket的系统调用,主要是参考大神的
Socket系统调用对应的内核函数为:
asmlinkage long sys_socket(int family, int type, int protocol)
{
int retval;
struct socket *sock;
{
int retval;
struct socket *sock;
/* 根据协议族、套口类型、传输层协议创建套口 */
retval = sock_create(family, type, protocol, &sock);
if (retval < 0)
goto out;
retval = sock_create(family, type, protocol, &sock);
if (retval < 0)
goto out;
/* 为创建的套接口分配一个文件描述符并进行绑定 */
retval = sock_map_fd(sock);
if (retval < 0)
goto out_release;
retval = sock_map_fd(sock);
if (retval < 0)
goto out_release;
out:
/* It may be already another descriptor 8) Not kernel problem. */
return retval;
/* It may be already another descriptor 8) Not kernel problem. */
return retval;
out_release:
sock_release(sock);
return retval;
}
sock_release(sock);
return retval;
}
sock_create函数:
int sock_create(int family, int type, int protocol, struct socket **res)
{
/* 传入0表示是用户态进程创建套接口 */
return __sock_create(family, type, protocol, res, 0);
}
__sock_create(family, type, protocol, res, 0);
/**
* 创建一个套接口
* family: 套接口协议族
* type: 套接口类型
* protocol: 传输层协议
* res: 输出参数,创建成功的套接口指针
* kern: 由内核还是应用程序创建。
*/
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
{
int err;
struct socket *sock;
{
/* 传入0表示是用户态进程创建套接口 */
return __sock_create(family, type, protocol, res, 0);
}
__sock_create(family, type, protocol, res, 0);
/**
* 创建一个套接口
* family: 套接口协议族
* type: 套接口类型
* protocol: 传输层协议
* res: 输出参数,创建成功的套接口指针
* kern: 由内核还是应用程序创建。
*/
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
{
int err;
struct socket *sock;
/*
* Check protocol is in range
*/
if (family < 0 || family >= NPROTO)/* 参数合法性检测 */
return -EAFNOSUPPORT;
if (type < 0 || type >= SOCK_MAX)
return -EINVAL;
/**
* IPV4协议族的SOCK_PACKET类型套接口已经不被支持
* 为兼容旧程序,转换为PF_PACKET */
if (family == PF_INET && type == SOCK_PACKET) {
static int warned;
if (!warned) {
warned = 1;
printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
}
family = PF_PACKET;
}
* Check protocol is in range
*/
if (family < 0 || family >= NPROTO)/* 参数合法性检测 */
return -EAFNOSUPPORT;
if (type < 0 || type >= SOCK_MAX)
return -EINVAL;
/**
* IPV4协议族的SOCK_PACKET类型套接口已经不被支持
* 为兼容旧程序,转换为PF_PACKET */
if (family == PF_INET && type == SOCK_PACKET) {
static int warned;
if (!warned) {
warned = 1;
printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
}
family = PF_PACKET;
}
/* 由安全模块对创建过程进行审计 */
err = security_socket_create(family, type, protocol, kern);
if (err)
return err;
#if defined(CONFIG_KMOD)
/* Attempt to load a protocol module if the find failed.
*
* 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
* requested real, full-featured networking support upon configuration.
* Otherwise module support will break!
*/
if (net_families[family]==NULL)/* 相应的协议族在内核中尚不存在,加载模块以支持该协议族 */
{
request_module("net-pf-%d",family);
}
#endif
err = security_socket_create(family, type, protocol, kern);
if (err)
return err;
#if defined(CONFIG_KMOD)
/* Attempt to load a protocol module if the find failed.
*
* 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
* requested real, full-featured networking support upon configuration.
* Otherwise module support will break!
*/
if (net_families[family]==NULL)/* 相应的协议族在内核中尚不存在,加载模块以支持该协议族 */
{
request_module("net-pf-%d",family);
}
#endif
/* 等待,直到锁被释放 */
net_family_read_lock();
if (net_families[family] == NULL) {/* 如果协议族仍然不存在,说明不支持此协议族 */
err = -EAFNOSUPPORT;
goto out;
}
net_family_read_lock();
if (net_families[family] == NULL) {/* 如果协议族仍然不存在,说明不支持此协议族 */
err = -EAFNOSUPPORT;
goto out;
}
/*
* Allocate the socket and allow the family to set things up. if
* the protocol is 0, the family is instructed to select an appropriate
* default.
*/
* Allocate the socket and allow the family to set things up. if
* the protocol is 0, the family is instructed to select an appropriate
* default.
*/
if (!(sock = sock_alloc())) {/* 分配与inode关联的套接口 */
printk(KERN_WARNING "socket: no more sockets\n");
err = -ENFILE; /* Not exactly a match, but its the
closest posix thing */
goto out;
}
printk(KERN_WARNING "socket: no more sockets\n");
err = -ENFILE; /* Not exactly a match, but its the
closest posix thing */
goto out;
}
sock->type = type;/* 设置套接口类型。 */
/*
* We will call the ->create function, that possibly is in a loadable
* module, so we have to bump that loadable module refcnt first.
*/
err = -EAFNOSUPPORT;
if (!try_module_get(net_families[family]->owner))/* 增加对协议族模块的引用,如果失败则退出 */
goto out_release;
* We will call the ->create function, that possibly is in a loadable
* module, so we have to bump that loadable module refcnt first.
*/
err = -EAFNOSUPPORT;
if (!try_module_get(net_families[family]->owner))/* 增加对协议族模块的引用,如果失败则退出 */
goto out_release;
/* 调用协议族的创建方法,对IPV4来说,调用的是inet_create */
if ((err = net_families[family]->create(sock, protocol)) < 0)
goto out_module_put;
/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
*/
if (!try_module_get(sock->ops->owner)) {/* 增加传输层模块的引用计数 */
sock->ops = NULL;
goto out_module_put;
}
/*
* Now that we're done with the ->create function, the [loadable]
* module can have its refcnt decremented
*/
/* 增加了传输层模块的引用计数后,可以释放协议族的模块引用计数 */
module_put(net_families[family]->owner);
*res = sock;
/* 通知安全模块,对创建过程进行检查。 */
security_socket_post_create(sock, family, type, protocol, kern);
if ((err = net_families[family]->create(sock, protocol)) < 0)
goto out_module_put;
/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
*/
if (!try_module_get(sock->ops->owner)) {/* 增加传输层模块的引用计数 */
sock->ops = NULL;
goto out_module_put;
}
/*
* Now that we're done with the ->create function, the [loadable]
* module can have its refcnt decremented
*/
/* 增加了传输层模块的引用计数后,可以释放协议族的模块引用计数 */
module_put(net_families[family]->owner);
*res = sock;
/* 通知安全模块,对创建过程进行检查。 */
security_socket_post_create(sock, family, type, protocol, kern);
out:
net_family_read_unlock();
return err;
out_module_put:
module_put(net_families[family]->owner);
out_release:
sock_release(sock);
goto out;
}
net_family_read_unlock();
return err;
out_module_put:
module_put(net_families[family]->owner);
out_release:
sock_release(sock);
goto out;
}
sock_create函数申请了一个struct socket结构体sock,又调用pf->create指向的函数对通过sock
进行初始化。分析inet_init等网络子系统初始化函数得知,pf->create指向的是inet_create函数
进行初始化。分析inet_init等网络子系统初始化函数得知,pf->create指向的是inet_create函数
/*
* Create an inet socket.
*/
/**
* 创建一个IPV4的socket
* sock: 已经创建的套接口
* protocol: 套接口的协议号
*/
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct list_head *p;
struct inet_protosw *answer;
struct inet_sock *inet;
struct proto *answer_prot;
unsigned char answer_flags;
char answer_no_check;
int err;
sock->state = SS_UNCONNECTED;/* 初始化套接口状态 */
/* Look for the requested type/protocol pair. */
answer = NULL;
rcu_read_lock();
list_for_each_rcu(p, &inetsw[sock->type]) {/* 根据套接口类型遍历IPV4链表 */
answer = list_entry(p, struct inet_protosw, list);
answer = NULL;
rcu_read_lock();
list_for_each_rcu(p, &inetsw[sock->type]) {/* 根据套接口类型遍历IPV4链表 */
answer = list_entry(p, struct inet_protosw, list);
/* Check the non-wild match. */
if (protocol == answer->protocol) {/* 比较传输层协议 */
if (protocol != IPPROTO_IP)
break;
} else {
/* Check for the two wild cases. */
if (IPPROTO_IP == protocol) {
protocol = answer->protocol;
break;
}
if (IPPROTO_IP == answer->protocol)
break;
}
answer = NULL;
}
if (protocol == answer->protocol) {/* 比较传输层协议 */
if (protocol != IPPROTO_IP)
break;
} else {
/* Check for the two wild cases. */
if (IPPROTO_IP == protocol) {
protocol = answer->protocol;
break;
}
if (IPPROTO_IP == answer->protocol)
break;
}
answer = NULL;
}
err = -ESOCKTNOSUPPORT;
if (!answer)/* 找不到对应的传输层协议 */
goto out_rcu_unlock;
err = -EPERM;
/* 创建该类型的套接口需要特定能力,而当前进程没有这种能力,则退出 */
if (answer->capability > 0 && !capable(answer->capability))
goto out_rcu_unlock;
err = -EPROTONOSUPPORT;
if (!protocol)
goto out_rcu_unlock;
if (!answer)/* 找不到对应的传输层协议 */
goto out_rcu_unlock;
err = -EPERM;
/* 创建该类型的套接口需要特定能力,而当前进程没有这种能力,则退出 */
if (answer->capability > 0 && !capable(answer->capability))
goto out_rcu_unlock;
err = -EPROTONOSUPPORT;
if (!protocol)
goto out_rcu_unlock;
/* 设置套接口层的接口 */
sock->ops = answer->ops;
answer_prot = answer->prot;
answer_no_check = answer->no_check;
answer_flags = answer->flags;
rcu_read_unlock();
sock->ops = answer->ops;
answer_prot = answer->prot;
answer_no_check = answer->no_check;
answer_flags = answer->flags;
rcu_read_unlock();
BUG_TRAP(answer_prot->slab != NULL);
err = -ENOBUFS;
/* 根据协议族等参数分配传输控制块。 */
sk = sk_alloc(PF_INET, GFP_KERNEL,
answer_prot->slab_obj_size,
answer_prot->slab);
if (sk == NULL)
goto out;
/* 根据协议族等参数分配传输控制块。 */
sk = sk_alloc(PF_INET, GFP_KERNEL,
answer_prot->slab_obj_size,
answer_prot->slab);
if (sk == NULL)
goto out;
err = 0;
sk->sk_prot = answer_prot;
/* 设置是否需要校验和 */
sk->sk_no_check = answer_no_check;
/* 是否可以重用地址和端口 */
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = 1;
sk->sk_prot = answer_prot;
/* 设置是否需要校验和 */
sk->sk_no_check = answer_no_check;
/* 是否可以重用地址和端口 */
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = 1;
inet = inet_sk(sk);
if (SOCK_RAW == sock->type) {/* 是原始套接口 */
inet->num = protocol;/* 设置本地端口为协议号 */
if (IPPROTO_RAW == protocol)/* 如果是RAW协议,则需要自己构建IP首部 */
inet->hdrincl = 1;
}
inet->num = protocol;/* 设置本地端口为协议号 */
if (IPPROTO_RAW == protocol)/* 如果是RAW协议,则需要自己构建IP首部 */
inet->hdrincl = 1;
}
if (ipv4_config.no_pmtu_disc)/* 是否支持PMTU */
inet->pmtudisc = IP_PMTUDISC_DONT;
else
inet->pmtudisc = IP_PMTUDISC_WANT;
inet->pmtudisc = IP_PMTUDISC_DONT;
else
inet->pmtudisc = IP_PMTUDISC_WANT;
inet->id = 0;
sock_init_data(sock, sk);/* 初始化传输控制块 */
sk_set_owner(sk, sk->sk_prot->owner);
sk_set_owner(sk, sk->sk_prot->owner);
/* 在套接口被释放时,进行一些清理工作。 */
sk->sk_destruct = inet_sock_destruct;
/* 设置协议族和协议号 */
sk->sk_family = PF_INET;
sk->sk_protocol = protocol;
/* 设置后备队列接收函数。 */
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
sk->sk_destruct = inet_sock_destruct;
/* 设置协议族和协议号 */
sk->sk_family = PF_INET;
sk->sk_protocol = protocol;
/* 设置后备队列接收函数。 */
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
inet->uc_ttl = -1;
inet->mc_loop = 1;
inet->mc_ttl = 1;
inet->mc_index = 0;
inet->mc_list = NULL;
inet->mc_loop = 1;
inet->mc_ttl = 1;
inet->mc_index = 0;
inet->mc_list = NULL;
#ifdef INET_REFCNT_DEBUG
atomic_inc(&inet_sock_nr);
#endif
atomic_inc(&inet_sock_nr);
#endif
if (inet->num) {/* 如果设置了本地端口号 */
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
inet->sport = htons(inet->num);/* 设置网络序的本地端口号 */
/* Add to protocol hash chains. */
sk->sk_prot->hash(sk);/* 将传输控制块加入到静列表中 */
}
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
inet->sport = htons(inet->num);/* 设置网络序的本地端口号 */
/* Add to protocol hash chains. */
sk->sk_prot->hash(sk);/* 将传输控制块加入到静列表中 */
}
if (sk->sk_prot->init) {/* 调用传输层的初始化回调,对TCP来说,就是tcp_v4_init_sock。UDP没有设置回调 */
err = sk->sk_prot->init(sk);
if (err)
sk_common_release(sk);
}
out:
return err;
out_rcu_unlock:
rcu_read_unlock();
goto out;
}
err = sk->sk_prot->init(sk);
if (err)
sk_common_release(sk);
}
out:
return err;
out_rcu_unlock:
rcu_read_unlock();
goto out;
}
经过协议和类型的匹配后,answer->ops指向的是inet_stream_ops,answer->prot指向的是tcp_prot:
/*
分配传输控制块
*/
struct sock *sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab)
{
struct sock *sk = NULL;
if (!slab)/* 如果传输层没有指定缓存分配区,则默认使用sk_cachep */
slab = sk_cachep;
/**
* 在指定的分配区中,用指定的分配参数分配传输控制块。
*/
sk = kmem_cache_alloc(slab, priority);
if (sk) {
if (zero_it) {/* 需要初始化它 */
memset(sk, 0,
zero_it == 1 ? sizeof(struct sock) : zero_it);
sk->sk_family = family;
sock_lock_init(sk);
}
/* 释放时需要使用 */
sk->sk_slab = slab;
if (security_sk_alloc(sk, family, priority)) {/* 安全审计,如果失败则释放传输层接口 */
kmem_cache_free(slab, sk);
sk = NULL;
}
}
return sk;
}
slab = sk_cachep;
/**
* 在指定的分配区中,用指定的分配参数分配传输控制块。
*/
sk = kmem_cache_alloc(slab, priority);
if (sk) {
if (zero_it) {/* 需要初始化它 */
memset(sk, 0,
zero_it == 1 ? sizeof(struct sock) : zero_it);
sk->sk_family = family;
sock_lock_init(sk);
}
/* 释放时需要使用 */
sk->sk_slab = slab;
if (security_sk_alloc(sk, family, priority)) {/* 安全审计,如果失败则释放传输层接口 */
kmem_cache_free(slab, sk);
sk = NULL;
}
}
return sk;
}
sock_init_data函数:
void sock_init_data(struct socket *sock, struct sock *sk)
{
skb_queue_head_init(&sk->sk_receive_queue);
skb_queue_head_init(&sk->sk_write_queue);
skb_queue_head_init(&sk->sk_error_queue);
{
skb_queue_head_init(&sk->sk_receive_queue);
skb_queue_head_init(&sk->sk_write_queue);
skb_queue_head_init(&sk->sk_error_queue);
sk->sk_send_head = NULL;
init_timer(&sk->sk_timer);
sk->sk_allocation = GFP_KERNEL;
sk->sk_rcvbuf = sysctl_rmem_default;
sk->sk_sndbuf = sysctl_wmem_default;
sk->sk_state = TCP_CLOSE;
sk->sk_zapped = 1;
sk->sk_socket = sock;
sk->sk_allocation = GFP_KERNEL;
sk->sk_rcvbuf = sysctl_rmem_default;
sk->sk_sndbuf = sysctl_wmem_default;
sk->sk_state = TCP_CLOSE;
sk->sk_zapped = 1;
sk->sk_socket = sock;
if(sock)
{
sk->sk_type = sock->type;
sk->sk_sleep = &sock->wait;
sock->sk = sk;
} else
sk->sk_sleep = NULL;
{
sk->sk_type = sock->type;
sk->sk_sleep = &sock->wait;
sock->sk = sk;
} else
sk->sk_sleep = NULL;
rwlock_init(&sk->sk_dst_lock);
rwlock_init(&sk->sk_callback_lock);
rwlock_init(&sk->sk_callback_lock);
sk->sk_state_change = sock_def_wakeup;
sk->sk_data_ready = sock_def_readable;
sk->sk_write_space = sock_def_write_space;
sk->sk_error_report = sock_def_error_report;
sk->sk_destruct = sock_def_destruct;
sk->sk_data_ready = sock_def_readable;
sk->sk_write_space = sock_def_write_space;
sk->sk_error_report = sock_def_error_report;
sk->sk_destruct = sock_def_destruct;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
sk->sk_sndmsg_off = 0;
sk->sk_peercred.pid = 0;
sk->sk_peercred.uid = -1;
sk->sk_peercred.gid = -1;
sk->sk_write_pending = 0;
sk->sk_rcvlowat = 1;
sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sk_owner = NULL;
sk->sk_peercred.uid = -1;
sk->sk_peercred.gid = -1;
sk->sk_write_pending = 0;
sk->sk_rcvlowat = 1;
sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sk_owner = NULL;
sk->sk_stamp.tv_sec = -1L;
sk->sk_stamp.tv_usec = -1L;
sk->sk_stamp.tv_usec = -1L;
atomic_set(&sk->sk_refcnt, 1);
}
sock_create函数的功能:创建一个struct socket类型的变量sock,找到TCP对应的操作
函数集inet_stream_ops并安装到sock->ops中;再申请一个struct tcp_sock结构体大小
的内存并强制赋给struct sock指针sk,使sk->prot指向tcp_prot,将sk赋给sock->sk使
得sock与sk关联起来,并对sk和sock进行初始化。而sock->ops和sk->prot的指向,决定
了后续所有系统调用的行为集。
}
sock_create函数的功能:创建一个struct socket类型的变量sock,找到TCP对应的操作
函数集inet_stream_ops并安装到sock->ops中;再申请一个struct tcp_sock结构体大小
的内存并强制赋给struct sock指针sk,使sk->prot指向tcp_prot,将sk赋给sock->sk使
得sock与sk关联起来,并对sk和sock进行初始化。而sock->ops和sk->prot的指向,决定
了后续所有系统调用的行为集。
sock_map_fd函数:
/**
* 将套接口与文件描述符绑定。
*/
int sock_map_fd(struct socket *sock)
{
int fd;
struct qstr this;
char name[32];
* 将套接口与文件描述符绑定。
*/
int sock_map_fd(struct socket *sock)
{
int fd;
struct qstr this;
char name[32];
/*
* Find a file descriptor suitable for return to the user.
*/
/**
* 获得空闲的文件描述符。
*/
fd = get_unused_fd();
if (fd >= 0) {/* 成功分配文件描述符 */
struct file *file = get_empty_filp();
* Find a file descriptor suitable for return to the user.
*/
/**
* 获得空闲的文件描述符。
*/
fd = get_unused_fd();
if (fd >= 0) {/* 成功分配文件描述符 */
struct file *file = get_empty_filp();
if (!file) {
put_unused_fd(fd);
fd = -ENFILE;
goto out;
}
put_unused_fd(fd);
fd = -ENFILE;
goto out;
}
sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
this.name = name;
this.len = strlen(name);
this.hash = SOCK_INODE(sock)->i_ino;
this.name = name;
this.len = strlen(name);
this.hash = SOCK_INODE(sock)->i_ino;
/**
* 分配文件目录项。
*/
file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
if (!file->f_dentry) {
put_filp(file);
put_unused_fd(fd);
fd = -ENOMEM;
goto out;
}
file->f_dentry->d_op = &sockfs_dentry_operations;
d_add(file->f_dentry, SOCK_INODE(sock));
file->f_vfsmnt = mntget(sock_mnt);
file->f_mapping = file->f_dentry->d_inode->i_mapping;
* 分配文件目录项。
*/
file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
if (!file->f_dentry) {
put_filp(file);
put_unused_fd(fd);
fd = -ENOMEM;
goto out;
}
file->f_dentry->d_op = &sockfs_dentry_operations;
d_add(file->f_dentry, SOCK_INODE(sock));
file->f_vfsmnt = mntget(sock_mnt);
file->f_mapping = file->f_dentry->d_inode->i_mapping;
sock->file = file;
file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
file->f_mode = FMODE_READ | FMODE_WRITE;
file->f_flags = O_RDWR;
file->f_pos = 0;
/* 将文件描述符实例增加到已经打开的文件列表中,完成文件与进程的绑定 */
fd_install(fd, file);
}
file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
file->f_mode = FMODE_READ | FMODE_WRITE;
file->f_flags = O_RDWR;
file->f_pos = 0;
/* 将文件描述符实例增加到已经打开的文件列表中,完成文件与进程的绑定 */
fd_install(fd, file);
}
out:
return fd;
}
可见sock_map_fd函数的功能是:获取一个未被使用的整数fd,申请一个文件结构体对象newfile,将fd与newfile关联起来。
void fastcall fd_install(unsigned int fd, struct file * file)
{
struct files_struct *files = current->files;
spin_lock(&files->file_lock);
if (unlikely(files->fd[fd] != NULL))
BUG();
files->fd[fd] = file;
spin_unlock(&files->file_lock);
}
对文件的读写等操作由文件系统inode的i_fop指向的函数集实现,在socket结构体中这个函数集是socket_file_ops:
return fd;
}
可见sock_map_fd函数的功能是:获取一个未被使用的整数fd,申请一个文件结构体对象newfile,将fd与newfile关联起来。
void fastcall fd_install(unsigned int fd, struct file * file)
{
struct files_struct *files = current->files;
spin_lock(&files->file_lock);
if (unlikely(files->fd[fd] != NULL))
BUG();
files->fd[fd] = file;
spin_unlock(&files->file_lock);
}
对文件的读写等操作由文件系统inode的i_fop指向的函数集实现,在socket结构体中这个函数集是socket_file_ops:
/**
* 套接口文件的接口
*/
static struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.aio_read = sock_aio_read,
.aio_write = sock_aio_write,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
.mmap = sock_mmap,
.open = sock_no_open, /* special open code to disallow open via /proc */
.release = sock_close,
.fasync = sock_fasync,
.readv = sock_readv,
.writev = sock_writev,
.sendpage = sock_sendpage
};
* 套接口文件的接口
*/
static struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.aio_read = sock_aio_read,
.aio_write = sock_aio_write,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
.mmap = sock_mmap,
.open = sock_no_open, /* special open code to disallow open via /proc */
.release = sock_close,
.fasync = sock_fasync,
.readv = sock_readv,
.writev = sock_writev,
.sendpage = sock_sendpage
};
sock_map_fd函数的功能了:将socke结构体对象与文件系统结构关联起来,
使得socket成为了一种特殊的文件系统;并生成一个文件描述符,将描述
符与socket文件系统关联,使得Linux API接口可以通过文件描述符操作socket。
将socket与文件系统关联起来是符合Unix系统“Everything is a file”的
理念的。但这样做有什么好处呢?我能想到的好处有两点:一是在socket上
产生的事件可以和其它类型文件系统的事件一起交由poll或epoll这类高效
的事件监控机制管理,这样可以大大扩展socket的应用范围;二是进程无
论是正常退出还是异常退出,内核在销毁进程的资源时都会关闭其打开的
所有文件描述符,这样即使进程被异常杀死,也会触发close系统调用将
socket对应的连接关掉(如果是TCP连接的话会通知对端关闭连接),这就
使得异常情况下网络连接的资源也能及时得到回收。
理念的。但这样做有什么好处呢?我能想到的好处有两点:一是在socket上
产生的事件可以和其它类型文件系统的事件一起交由poll或epoll这类高效
的事件监控机制管理,这样可以大大扩展socket的应用范围;二是进程无
论是正常退出还是异常退出,内核在销毁进程的资源时都会关闭其打开的
所有文件描述符,这样即使进程被异常杀死,也会触发close系统调用将
socket对应的连接关掉(如果是TCP连接的话会通知对端关闭连接),这就
使得异常情况下网络连接的资源也能及时得到回收。
总结一下socket系统调用的功能:
在内核生成一个socket和tcp_sock类型的
对象用于保存TCP连接信息,并安装TCP相关的操作函数集以限定后续的系统
调用的行为;将socket对象与一个file类型的对象绑定到一起,并将一个文
件描述符与file对象绑定到一起,最后将这个文件描述符返回给调用者。
在内核生成一个socket和tcp_sock类型的
对象用于保存TCP连接信息,并安装TCP相关的操作函数集以限定后续的系统
调用的行为;将socket对象与一个file类型的对象绑定到一起,并将一个文
件描述符与file对象绑定到一起,最后将这个文件描述符返回给调用者。