Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5760322
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类:

2007-12-26 11:45:33

socket系统调用的内核分析

王耀(wangyao@cs.hit.edu.cn)

socket函数是所有网络编程的第一个函数,这里我们来分析一下socket系统调用在内核中的实现。所有的网络系统调用,最终都会调用sys_socketcall这个系统调用,由它来进行多路复用分解,分别调用相应的处理函数,socket函数对应调用sys_socket函数。

sys_socket函数调用sock_create函数来创建struct socket,并初始化它。调用后得到一个struct socket。最后,调用sock_map_fd找一个空闲的文件描述符,映射到这个创建好的套接字上,将这个文件描述符返回。

socket调用关系图(以TCP Socket进行分析):


看上面的调用关系图,看到在sys_socket函数中,有一步是调用net_families[family]->create完成最后的创建工作,下面就以inet域的创建来解释这最后一步的创建工作:

1、设socket->state = SS_UNCONNECTED

2、从数组inetsw中匹配套接字类型和协议类型。inetsw是一个链表数组,也就是说数组的每一项是一个链表,同套接字类型的在同一个链表中。比如,用户这样创建一个TCP协议的套接字:
socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )

最终,内核在inetsw中匹配到的是这样一个结构体:
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,
}
}

这里最关键的是prot成员和ops成员,tcp_prot将提供TCP协议相关的全部操作,inet_stream_ops将提供域相关的全部操作,包括listen, connect等。


注意:

这里需要注意protoproto_ops的数据区别,proto中的操作函数,是针对sock结构体的,在网络层;proto_ops是针对socket结构体的,在BSD套接字层。proto_ops中的操作函数的实现,是通过调用proto中的操作函数来实现的。proto中的操作函数更底层一些。

struct proto中的accept函数:

struct sock * (*accept) (struct sock *sk, int flags, int *err);

struct proto_ops中的accept函数:

int (*accept) (struct socket *sock,struct socket *newsock, int flags);

我们这里分析一个操作函数:

inet_stream_ops中的accept函数,指定的是inet_accept函数;tcp_prot中的accept函数,指定的是inet_csk_accept函数。

inet_accept函数中:

struct sock *sk1 = sock->sk;

struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err);

inet_accept函数中调用了tcp_prot中的accept函数,即inet_csk_accept函数。


3
socket->ops = 匹配到的那个ops
4
、分配socket->sock
5
、让struct inet_sock指向socket->sockstruct inet_sockstruct sock的超集。其头部内容即为struct sock
6
、为inet_socksocket->sock的成员赋初始值。这里,我们可以看到一些平时我们比较关心的问题,比如:inet->mc_ttl = 1
7
、调用socket->sock->sk_prot->init(...)完成整个创建过程。

描述到这里,一个最为粗糙的socket创建过程算是完成了,但留下的问题却更多了,因为它涉及到很多宠大的结构体,其内容与socket的正常工作都息息相关,希望此文能够对大家了解socket的内核实现有所帮助。


分析中常用的数据结构及其常用引用名:

struct socket *sock;

struct sock *sk;

struct sk_buff *skb;

struct proto tcp_prot;

struct proto_ops inet_stream_ops;

static struct list_head inetsw[SOCK_MAX];

static struct inet_protosw inetsw_array[];

分析中一些初始化函数:

static int __init sock_init(void)

static int __init inet_init(void)

proto_register(&tcp_prot, 1);

sock_register(&inet_family_ops);

inet_add_protocol(&tcp_protocol, IPPROTO_TCP);

void inet_register_protosw(struct inet_protosw *p);

dev_add_pack(&ip_packet_type);

一些数据结构的头部包含关系:



阅读(4297) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~