我们先了解socket数据结构的定义,它在include/linux/net.h 中.
/** * struct socket - general BSD socket * @state: socket state (%SS_CONNECTED, etc) * @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc) * @ops: protocol specific socket operations * @fasync_list: Asynchronous wake up list * @file: File back pointer for gc * @sk: internal networking protocol agnostic socket representation * @wait: wait queue for several uses * @type: socket type (%SOCK_STREAM, etc) */ struct socket { socket_state state; unsigned long flags; const struct proto_ops *ops; struct fasync_struct *fasync_list; struct file *file; struct sock *sk; wait_queue_head_t wait; short type; };代码清单 2.1 是通用BSD的socket定义。特别应该注意的是sock 结构变量,这个结构的定
义非常大,sock结构体是根据使用的协议而挂入socket, 每一种协议都有此结构变量,之所
以从socket 中分离出sock一个这样重要的结构是因为socket 是通用的套接字结构体,
而sock 与具体使用的协议相关。总之,公共的通用部分放大socket 结构中,而通用部分
的放大sock结构,这就是sock的定义内容较少而sock定义的内容相对庞大的原因。
分配并初始化 socket 结构
创建socket 的函数sys_socket(), 在这个函数中调用sock_creat() 来完成
创建。这个函数在/net/socket.c中:
int sock_create(int family, int type, int protocol, struct socket **res) { return __sock_create(family, type, protocol, res, 0); }函数实际是调用sock_create() 来执行创建任务的,这个函数在同一个
文件中。
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern) { int err; struct socket *sock; const struct net_proto_family *pf; /* * Check protocol is in range */ if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; if (type < 0 || type >= SOCK_MAX) return -EINVAL; /* Compatibility. This uglymoron is moved from INET layer to here to avoid deadlock in module load. */ 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; /* * 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. */ sock = sock_alloc(); if (!sock) { if (net_ratelimit()) printk(KERN_WARNING "socket: no more sockets\n"); return -ENFILE; /* Not exactly a match, but its the closest posix thing */ } sock->type = type; #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 rcu_read_lock(); pf = rcu_dereference(net_families[family]); err = -EAFNOSUPPORT; if (!pf) 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. */ if (!try_module_get(pf->owner)) goto out_release; /* Now protected by module ref count */ rcu_read_unlock(); err = pf->create(sock, protocol); if (err < 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)) goto out_module_busy; /* * Now that we're done with the ->create function, the [loadable] * module can have its refcnt decremented */ module_put(pf->owner); err = security_socket_post_create(sock, family, type, protocol, kern); if (err) goto out_sock_release; *res = sock; return 0; out_module_busy: err = -EAFNOSUPPORT; out_module_put: sock->ops = NULL; module_put(pf->owner); out_sock_release: sock_release(sock); return err; out_release: rcu_read_unlock(); goto out_sock_release; }sock_alloc为服务器程序分配socket结构和文件节点。
/** * sock_alloc - allocate a socket * * Allocate a new inode and socket object. The two are bound together * and initialised. The socket is then returned. If we are out of inodes * NULL is returned. */ static struct socket *sock_alloc(void) { struct inode *inode; struct socket *sock; inode = new_inode(sock_mnt->mnt_sb); if (!inode) return NULL; sock = SOCKET_I(inode); inode->i_mode = S_IFSOCK | S_IRWXUGO; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; get_cpu_var(sockets_in_use)++; put_cpu_var(sockets_in_use); return sock; }代码涉及文件系统的inode 文件节点,调用new_inode() 分配节点,
sock_mnt是socket网络文件的根节点。这里是在socket网络文件系统
中分配一个inode节点,分配节点生服务器程序便可以通过函数read()
和write() 找到socket 进行读/写操作。