查看: 511|回复: 2

tcp/ip协议socket创建详解

 关闭 [复制链接]

签到天数: 21 天

连续签到: 0 天

[LV.4]偶尔看看III

发表于 2009-2-15 08:52 | 显示全部楼层 |阅读模式
要分析套接字就不的不提到inode。套接字可以和文件关联,当然是和特殊的文件系统关联,这样就可象操作文件一样操作网络,给应用程序用户提供了极大的便利。既然可以是文件操作,就少不了INODE,由于要和socket关联,那么inode中应该有于socket相关的,事实上确实如此。
struct inode {
union {
struct minix_inode_info minix_i;
struct ext2_inode_infoext2_i;
struct ext3_inode_infoext3_i;
struct hpfs_inode_infohpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_infomsdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_infoisofs_i;
struct nfs_inode_infonfs_i;
struct sysv_inode_infosysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_infoufs_i;
struct efs_inode_infoefs_i;
struct romfs_inode_inforomfs_i;
struct shmem_inode_info shmem_i;
struct coda_inode_infocoda_i;
struct smb_inode_infosmbfs_i;
struct hfs_inode_infohfs_i;
struct adfs_inode_infoadfs_i;
struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_inforeiserfs_i;
struct bfs_inode_infobfs_i;
struct udf_inode_infoudf_i;
struct ncp_inode_info ncpfs_i;
struct proc_inode_infoproc_i;
struct socket socket_i;
struct usbdev_inode_infousbdev_i;
struct jffs2_inode_infojffs2_i;
void*generic_ip;
} u;
};
上面的u联合体中的socket_i就将socket和inode联系起来了。

有了上面的一点基础,现在我们就以tcp协议的套接字创建为例来分析socket创建过程。
当我们在应用程序调用API函数socket(AF_INET,SOCK_RAW,IPPROTO_TCP)时就会调用socket的系统调用进入统一的入口函数sys_socketcall,如果是创建套接字,就会调用sys_socket,sys_socket然后就调用sock_create,这个才是真正执行socket创建的函数。
Sys_socketcall->sys_socket->sock_create()-
int sock_create(int family, int type, int protocol, struct socket **res)
{
………
……..
if (!(sock = sock_alloc()))
{
printk(KERN_WARNING \"socket: no more sockets\\n\");
i = -ENFILE; /* Not exactly a match, but its the
closest posix thing */
goto out;
}
……..
………
}
Sock_create函数调用socket_alloc创建socket,主要分配两个主要数据,一个是套接字socket,另一个是socket对应的inode。

Sys_socketcall->sys_socket->sock_create()->sock_alloc

struct socket *sock_alloc(void)
{
struct inode * inode;
struct socket * sock;
//为当前套接字分配Inode
inode = get_empty_inode();
if (!inode)
return NULL;
//为套接字对应的Inode指定其文件系统的超级块,这个超级块其实不存在
//sock_mnt在kern_mount中创建,是具体文件系统的全局变量。
inode->i_sb = sock_mnt->mnt_sb;
// 获取Inode对应的socket结构来初始化
sock = socki_lookup(inode);//

inode->i_mode = S_IFSOCK|S_IRWXUGO;
inode->i_sock = 1;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;

sock->inode = inode;
init_waitqueue_head(&sock->wait);
sock->fasync_list = NULL;
sock->state = SS_UNCONNECTED;
sock->flags = 0;
sock->ops = NULL;
sock->sk = NULL;
sock->file = NULL;

sockets_in_use[smp_processor_id()].counter++;
return sock;
}
首先分配SOCK文件的INODE,然后将其与sockfs的sb联系起来,分配inode时其实已经分配了socket结构体,因为socket结构体是inode的成员,然后就初始化Inode和对应socket。Socket数据结构如下。
struct socket
{
socket_state state;

unsigned long flags;
struct proto_ops *ops;
//文件系统相关的接口file,inode
struct inode *inode;
struct fasync_struct*fasync_list; /* Asynchronous wake up list */
struct file*file;/* File back pointer for gc */
//网络关联的数据接口在sock中
struct sock*sk;
wait_queue_head_t wait;

short type;
unsigned charpasscred;
};
我们知道socket是只是网络和文件系统关联的接口抽象,没有网络的相关信息,从socket的数据结构容易看出,所以还有另一个网络抽象的重要的数据结构sock。
因此所以肯定有一个创建sock的函数,这个函数就是在sock_alloc返回到sock_Create中调用的
Sock_create:(){
………

if ((i = net_families[family]->create(sock, protocol))
{
sock_release(sock);
goto out;
}
……….
……….
}
调用具体family(ip,ipx等网络层协议)的create函数,net_families[]数组的元素代表一种网络层协议(ip,ipx)等的相关数据及操作,create函数就是其中一个操作。
在这里是调用inet_create,inet_create创建sock,并根据具体协议初始化它。
Sys_socketcall->sys_socket->sock_create()->inet_create
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct list_head *p;
struct inet_protosw *answer;
sock->state = SS_UNCONNECTED;
// sk_alloc实现sock结构分配
sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
//,然后初始化sock结构sk
list_for_each(p, &inetsw[sock->type]) {
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;
}
br_read_unlock_bh(BR_NETPROTO_LOCK);

if (!answer)
goto free_and_badtype;
if (answer->capability > 0 && !capable(answer->capability))
goto free_and_badperm;
if (!protocol)
goto free_and_noproto;

sock->ops = answer->ops;
sk->prot = answer->prot;
}
上面inetsw是inet_protosw数据结构数组,是很重要的数据结构,提供了具体传输层的一些函数集,是在net_init用inetsw_array赋值的。
Inet_init()
{
/* Register the socket-side information for inet_create. */
for(r = &inetsw[0]; r
INIT_LIST_HEAD(r);

for(q = inetsw_array; q
inet_register_protosw(q);
..........
}
static struct inet_protosw inetsw_array[] =
{
{
type:SOCK_STREAM,
protocol:IPPROTO_TCP,
//传输层级结构
prot:&tcp_prot,
//提供统一的
ops: &inet_stream_ops,
capability:-1,
no_check:0,
flags: INET_PROTOSW_PERMANENT,
},

{
type:SOCK_DGRAM,
protocol:IPPROTO_UDP,
prot:&udp_prot,
ops: &inet_dgram_ops,
capability:-1,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_PERMANENT,
},


{
type:SOCK_RAW,
protocol:IPPROTO_IP,/* wild card */
prot:&raw_prot,
ops: &inet_dgram_ops,
capability:CAP_NET_RAW,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_REUSE,
}
};
至此数据初始化完成了,然后就调用具体传输层协议的初始化函数。
总结一下,整个创建过程创建了三个重要的数据结构,inode,socket,sock。



整个创建过程主要函数调用层次关系如下:

Sock_create()//创建socket
->alloc_sock() //创建初始的socket
>get_empty_inode//获取一个Inode-
>socket_look_up()//填充具体inode的socket并初始化
->inet_create() //完善socket结构体内容,如添加sock结构。
->alloc_sk// 创建sock结构,并初始化socket->ops=inetsw[](具体// 协议的函数),sock->proto,
->tcp_init
PCOS系统下载站:http://zhuangji.wang

签到天数: 21 天

连续签到: 0 天

[LV.4]偶尔看看III

 楼主| 发表于 2009-2-15 08:52 | 显示全部楼层

tcp/ip协议socket创建详解

要分析套接字就不的不提到inode。套接字可以和文件关联,当然是和特殊的文件系统关联,这样就可象操作文件一样操作网络,给应用程序用户提供了极大的便利。既然可以是文件操作,就少不了INODE,由于要和socket关联,那么inode中应该有于socket相关的,事实上确实如此。
struct inode {
union {
struct minix_inode_info minix_i;
struct ext2_inode_infoext2_i;
struct ext3_inode_infoext3_i;
struct hpfs_inode_infohpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_infomsdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_infoisofs_i;
struct nfs_inode_infonfs_i;
struct sysv_inode_infosysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_infoufs_i;
struct efs_inode_infoefs_i;
struct romfs_inode_inforomfs_i;
struct shmem_inode_info shmem_i;
struct coda_inode_infocoda_i;
struct smb_inode_infosmbfs_i;
struct hfs_inode_infohfs_i;
struct adfs_inode_infoadfs_i;
struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_inforeiserfs_i;
struct bfs_inode_infobfs_i;
struct udf_inode_infoudf_i;
struct ncp_inode_info ncpfs_i;
struct proc_inode_infoproc_i;
struct socket socket_i;
struct usbdev_inode_infousbdev_i;
struct jffs2_inode_infojffs2_i;
void*generic_ip;
} u;
};
上面的u联合体中的socket_i就将socket和inode联系起来了。

有了上面的一点基础,现在我们就以tcp协议的套接字创建为例来分析socket创建过程。
当我们在应用程序调用API函数socket(AF_INET,SOCK_RAW,IPPROTO_TCP)时就会调用socket的系统调用进入统一的入口函数sys_socketcall,如果是创建套接字,就会调用sys_socket,sys_socket然后就调用sock_create,这个才是真正执行socket创建的函数。
Sys_socketcall->sys_socket->sock_create()-
int sock_create(int family, int type, int protocol, struct socket **res)
{
………
……..
if (!(sock = sock_alloc()))
{
printk(KERN_WARNING \"socket: no more sockets\\n\");
i = -ENFILE; /* Not exactly a match, but its the
closest posix thing */
goto out;
}
……..
………
}
Sock_create函数调用socket_alloc创建socket,主要分配两个主要数据,一个是套接字socket,另一个是socket对应的inode。

Sys_socketcall->sys_socket->sock_create()->sock_alloc

struct socket *sock_alloc(void)
{
struct inode * inode;
struct socket * sock;
//为当前套接字分配Inode
inode = get_empty_inode();
if (!inode)
return NULL;
//为套接字对应的Inode指定其文件系统的超级块,这个超级块其实不存在
//sock_mnt在kern_mount中创建,是具体文件系统的全局变量。
inode->i_sb = sock_mnt->mnt_sb;
// 获取Inode对应的socket结构来初始化
sock = socki_lookup(inode);//

inode->i_mode = S_IFSOCK|S_IRWXUGO;
inode->i_sock = 1;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;

sock->inode = inode;
init_waitqueue_head(&sock->wait);
sock->fasync_list = NULL;
sock->state = SS_UNCONNECTED;
sock->flags = 0;
sock->ops = NULL;
sock->sk = NULL;
sock->file = NULL;

sockets_in_use[smp_processor_id()].counter++;
return sock;
}
首先分配SOCK文件的INODE,然后将其与sockfs的sb联系起来,分配inode时其实已经分配了socket结构体,因为socket结构体是inode的成员,然后就初始化Inode和对应socket。Socket数据结构如下。
struct socket
{
socket_state state;

unsigned long flags;
struct proto_ops *ops;
//文件系统相关的接口file,inode
struct inode *inode;
struct fasync_struct*fasync_list; /* Asynchronous wake up list */
struct file*file;/* File back pointer for gc */
//网络关联的数据接口在sock中
struct sock*sk;
wait_queue_head_t wait;

short type;
unsigned charpasscred;
};
我们知道socket是只是网络和文件系统关联的接口抽象,没有网络的相关信息,从socket的数据结构容易看出,所以还有另一个网络抽象的重要的数据结构sock。
因此所以肯定有一个创建sock的函数,这个函数就是在sock_alloc返回到sock_Create中调用的
Sock_create:(){
………

if ((i = net_families[family]->create(sock, protocol))
{
sock_release(sock);
goto out;
}
……….
……….
}
调用具体family(ip,ipx等网络层协议)的create函数,net_families[]数组的元素代表一种网络层协议(ip,ipx)等的相关数据及操作,create函数就是其中一个操作。
在这里是调用inet_create,inet_create创建sock,并根据具体协议初始化它。
Sys_socketcall->sys_socket->sock_create()->inet_create
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct list_head *p;
struct inet_protosw *answer;
sock->state = SS_UNCONNECTED;
// sk_alloc实现sock结构分配
sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
//,然后初始化sock结构sk
list_for_each(p, &inetsw[sock->type]) {
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;
}
br_read_unlock_bh(BR_NETPROTO_LOCK);

if (!answer)
goto free_and_badtype;
if (answer->capability > 0 && !capable(answer->capability))
goto free_and_badperm;
if (!protocol)
goto free_and_noproto;

sock->ops = answer->ops;
sk->prot = answer->prot;
}
上面inetsw是inet_protosw数据结构数组,是很重要的数据结构,提供了具体传输层的一些函数集,是在net_init用inetsw_array赋值的。
Inet_init()
{
/* Register the socket-side information for inet_create. */
for(r = &inetsw[0]; r
INIT_LIST_HEAD(r);

for(q = inetsw_array; q
inet_register_protosw(q);
..........
}
static struct inet_protosw inetsw_array[] =
{
{
type:SOCK_STREAM,
protocol:IPPROTO_TCP,
//传输层级结构
prot:&tcp_prot,
//提供统一的
ops: &inet_stream_ops,
capability:-1,
no_check:0,
flags: INET_PROTOSW_PERMANENT,
},

{
type:SOCK_DGRAM,
protocol:IPPROTO_UDP,
prot:&udp_prot,
ops: &inet_dgram_ops,
capability:-1,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_PERMANENT,
},


{
type:SOCK_RAW,
protocol:IPPROTO_IP,/* wild card */
prot:&raw_prot,
ops: &inet_dgram_ops,
capability:CAP_NET_RAW,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_REUSE,
}
};
至此数据初始化完成了,然后就调用具体传输层协议的初始化函数。
总结一下,整个创建过程创建了三个重要的数据结构,inode,socket,sock。



整个创建过程主要函数调用层次关系如下:

Sock_create()//创建socket
->alloc_sock() //创建初始的socket
>get_empty_inode//获取一个Inode-
>socket_look_up()//填充具体inode的socket并初始化
->inet_create() //完善socket结构体内容,如添加sock结构。
->alloc_sk// 创建sock结构,并初始化socket->ops=inetsw[](具体// 协议的函数),sock->proto,
->tcp_init
PCOS系统下载站:http://zhuangji.wang

签到天数: 21 天

连续签到: 0 天

[LV.4]偶尔看看III

 楼主| 发表于 2009-2-15 08:52 | 显示全部楼层

tcp/ip协议socket创建详解

要分析套接字就不的不提到inode。套接字可以和文件关联,当然是和特殊的文件系统关联,这样就可象操作文件一样操作网络,给应用程序用户提供了极大的便利。既然可以是文件操作,就少不了INODE,由于要和socket关联,那么inode中应该有于socket相关的,事实上确实如此。
struct inode {
union {
struct minix_inode_info minix_i;
struct ext2_inode_infoext2_i;
struct ext3_inode_infoext3_i;
struct hpfs_inode_infohpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_infomsdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_infoisofs_i;
struct nfs_inode_infonfs_i;
struct sysv_inode_infosysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_infoufs_i;
struct efs_inode_infoefs_i;
struct romfs_inode_inforomfs_i;
struct shmem_inode_info shmem_i;
struct coda_inode_infocoda_i;
struct smb_inode_infosmbfs_i;
struct hfs_inode_infohfs_i;
struct adfs_inode_infoadfs_i;
struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_inforeiserfs_i;
struct bfs_inode_infobfs_i;
struct udf_inode_infoudf_i;
struct ncp_inode_info ncpfs_i;
struct proc_inode_infoproc_i;
struct socket socket_i;
struct usbdev_inode_infousbdev_i;
struct jffs2_inode_infojffs2_i;
void*generic_ip;
} u;
};
上面的u联合体中的socket_i就将socket和inode联系起来了。

有了上面的一点基础,现在我们就以tcp协议的套接字创建为例来分析socket创建过程。
当我们在应用程序调用API函数socket(AF_INET,SOCK_RAW,IPPROTO_TCP)时就会调用socket的系统调用进入统一的入口函数sys_socketcall,如果是创建套接字,就会调用sys_socket,sys_socket然后就调用sock_create,这个才是真正执行socket创建的函数。
Sys_socketcall->sys_socket->sock_create()-
int sock_create(int family, int type, int protocol, struct socket **res)
{
………
……..
if (!(sock = sock_alloc()))
{
printk(KERN_WARNING \"socket: no more sockets\\n\");
i = -ENFILE; /* Not exactly a match, but its the
closest posix thing */
goto out;
}
……..
………
}
Sock_create函数调用socket_alloc创建socket,主要分配两个主要数据,一个是套接字socket,另一个是socket对应的inode。

Sys_socketcall->sys_socket->sock_create()->sock_alloc

struct socket *sock_alloc(void)
{
struct inode * inode;
struct socket * sock;
//为当前套接字分配Inode
inode = get_empty_inode();
if (!inode)
return NULL;
//为套接字对应的Inode指定其文件系统的超级块,这个超级块其实不存在
//sock_mnt在kern_mount中创建,是具体文件系统的全局变量。
inode->i_sb = sock_mnt->mnt_sb;
// 获取Inode对应的socket结构来初始化
sock = socki_lookup(inode);//

inode->i_mode = S_IFSOCK|S_IRWXUGO;
inode->i_sock = 1;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;

sock->inode = inode;
init_waitqueue_head(&sock->wait);
sock->fasync_list = NULL;
sock->state = SS_UNCONNECTED;
sock->flags = 0;
sock->ops = NULL;
sock->sk = NULL;
sock->file = NULL;

sockets_in_use[smp_processor_id()].counter++;
return sock;
}
首先分配SOCK文件的INODE,然后将其与sockfs的sb联系起来,分配inode时其实已经分配了socket结构体,因为socket结构体是inode的成员,然后就初始化Inode和对应socket。Socket数据结构如下。
struct socket
{
socket_state state;

unsigned long flags;
struct proto_ops *ops;
//文件系统相关的接口file,inode
struct inode *inode;
struct fasync_struct*fasync_list; /* Asynchronous wake up list */
struct file*file;/* File back pointer for gc */
//网络关联的数据接口在sock中
struct sock*sk;
wait_queue_head_t wait;

short type;
unsigned charpasscred;
};
我们知道socket是只是网络和文件系统关联的接口抽象,没有网络的相关信息,从socket的数据结构容易看出,所以还有另一个网络抽象的重要的数据结构sock。
因此所以肯定有一个创建sock的函数,这个函数就是在sock_alloc返回到sock_Create中调用的
Sock_create:(){
………

if ((i = net_families[family]->create(sock, protocol))
{
sock_release(sock);
goto out;
}
……….
……….
}
调用具体family(ip,ipx等网络层协议)的create函数,net_families[]数组的元素代表一种网络层协议(ip,ipx)等的相关数据及操作,create函数就是其中一个操作。
在这里是调用inet_create,inet_create创建sock,并根据具体协议初始化它。
Sys_socketcall->sys_socket->sock_create()->inet_create
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct list_head *p;
struct inet_protosw *answer;
sock->state = SS_UNCONNECTED;
// sk_alloc实现sock结构分配
sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
//,然后初始化sock结构sk
list_for_each(p, &inetsw[sock->type]) {
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;
}
br_read_unlock_bh(BR_NETPROTO_LOCK);

if (!answer)
goto free_and_badtype;
if (answer->capability > 0 && !capable(answer->capability))
goto free_and_badperm;
if (!protocol)
goto free_and_noproto;

sock->ops = answer->ops;
sk->prot = answer->prot;
}
上面inetsw是inet_protosw数据结构数组,是很重要的数据结构,提供了具体传输层的一些函数集,是在net_init用inetsw_array赋值的。
Inet_init()
{
/* Register the socket-side information for inet_create. */
for(r = &inetsw[0]; r
INIT_LIST_HEAD(r);

for(q = inetsw_array; q
inet_register_protosw(q);
..........
}
static struct inet_protosw inetsw_array[] =
{
{
type:SOCK_STREAM,
protocol:IPPROTO_TCP,
//传输层级结构
prot:&tcp_prot,
//提供统一的
ops: &inet_stream_ops,
capability:-1,
no_check:0,
flags: INET_PROTOSW_PERMANENT,
},

{
type:SOCK_DGRAM,
protocol:IPPROTO_UDP,
prot:&udp_prot,
ops: &inet_dgram_ops,
capability:-1,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_PERMANENT,
},


{
type:SOCK_RAW,
protocol:IPPROTO_IP,/* wild card */
prot:&raw_prot,
ops: &inet_dgram_ops,
capability:CAP_NET_RAW,
no_check:UDP_CSUM_DEFAULT,
flags: INET_PROTOSW_REUSE,
}
};
至此数据初始化完成了,然后就调用具体传输层协议的初始化函数。
总结一下,整个创建过程创建了三个重要的数据结构,inode,socket,sock。



整个创建过程主要函数调用层次关系如下:

Sock_create()//创建socket
->alloc_sock() //创建初始的socket
>get_empty_inode//获取一个Inode-
>socket_look_up()//填充具体inode的socket并初始化
->inet_create() //完善socket结构体内容,如添加sock结构。
->alloc_sk// 创建sock结构,并初始化socket->ops=inetsw[](具体// 协议的函数),sock->proto,
->tcp_init
PCOS系统下载站:http://zhuangji.wang

本版积分规则