- 论坛徽章:
- 0
|
Linux2.6.30内核的sock结构
978计划工作组 2009-11-18
1函数源码
struct sock {
/*
* Now struct inet_timewait_sock also uses sock_common, so please just
* don't add nothing before this first member (__sk_common) --acme
*/
struct sock_common __sk_common;
#define sk_family __sk_common.skc_family
#define sk_state __sk_common.skc_state
#define sk_reuse __sk_common.skc_reuse
#define sk_bound_dev_if __sk_common.skc_bound_dev_if
#define sk_node __sk_common.skc_node
#define sk_nulls_node __sk_common.skc_nulls_node
#define sk_bind_node __sk_common.skc_bind_node
#define sk_refcnt __sk_common.skc_refcnt
#define sk_hash __sk_common.skc_hash
#define sk_prot __sk_common.skc_prot
#define sk_net __sk_common.skc_net
unsigned char sk_shutdown : 2,
sk_no_check : 2,
sk_userlocks : 4;
unsigned char sk_protocol;
unsigned short sk_type;
int sk_rcvbuf;
socket_lock_t sk_lock;
/*
* The backlog queue is special, it is always used with
* the per-socket spinlock held and requires low latency
* access. Therefore we special case it's implementation.
*/
struct {
struct sk_buff *head;
struct sk_buff *tail;
} sk_backlog;
wait_queue_head_t *sk_sleep;
struct dst_entry *sk_dst_cache;
#ifdef CONFIG_XFRM
struct xfrm_policy *sk_policy[2];
#endif
rwlock_t sk_dst_lock;
atomic_t sk_rmem_alloc;
atomic_t sk_wmem_alloc;
atomic_t sk_omem_alloc;
int sk_sndbuf;
struct sk_buff_head sk_receive_queue;
struct sk_buff_head sk_write_queue;
#ifdef CONFIG_NET_DMA
struct sk_buff_head sk_async_wait_queue;
#endif
int sk_wmem_queued;
int sk_forward_alloc;
gfp_t sk_allocation;
int sk_route_caps;
int sk_gso_type;
unsigned int sk_gso_max_size;
int sk_rcvlowat;
unsigned long sk_flags;
unsigned long sk_lingertime;
struct sk_buff_head sk_error_queue;
struct proto *sk_prot_creator;
rwlock_t sk_callback_lock;
int sk_err,
sk_err_soft;
atomic_t sk_drops;
unsigned short sk_ack_backlog;
unsigned short sk_max_ack_backlog;
__u32 sk_priority;
struct ucred sk_peercred;
long sk_rcvtimeo;
long sk_sndtimeo;
struct sk_filter *sk_filter;
void *sk_protinfo;
struct timer_list sk_timer;
ktime_t sk_stamp;
struct socket *sk_socket;
void *sk_user_data;
struct page *sk_sndmsg_page;
struct sk_buff *sk_send_head;
__u32 sk_sndmsg_off;
int sk_write_pending;
#ifdef CONFIG_SECURITY
void *sk_security;
#endif
__u32 sk_mark;
/* XXX 4 bytes hole on 64 bit */
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk, int bytes);
void (*sk_write_space)(struct sock *sk);
void (*sk_error_report)(struct sock *sk);
int (*sk_backlog_rcv)(struct sock *sk,
struct sk_buff *skb);
void (*sk_destruct)(struct sock *sk);
};
2结构用途
sock结构是对socket结构的扩充,与文件系统相关的域放在socket结构中了,而与网络相关的域放在了sock结构中了,目的是在非网络数据结构中定义socket域时无需包括整个sock结构,而只分配一个sock结构的指针即可,这样可以大大的节约内存。
3语句注释
3.1 成员注释
struct sock_common __sk_common
网络层的最常用属性放在此结构中了,如地址族、连接状态等。详细信息参见sock_common结构。
unsigned char sk_shutdown : 2
标示了socket关闭的情况,关于关闭的情况有3种,如下所示:
SHUTDOWN_MASK:宏值为3,表示完全关闭。
RCV_SHUTDOWN:宏值为1 :接收通道被关闭(远端发送了FIN 数据包)。
SEND_SHUTDOWN:发送通道关闭(本地主动发送FIN 数据包)。
unsigned char sk_no_check : 2
打开或关闭校验和。
unsigned char sk_userlocks : 4
用户锁标志,有四种锁,共占四位,如下所示:
SOCK_SNDBUF_LOCK :宏值为1,sk_userlocks的第0位(最低位为0位)为1时不可以修改sk_sndbuf的值,即如果锁了就不可以修改此值。
SOCK_RCVBUF_LOCK :宏值为2,sk_userlocks的第1位(最低位为0位)为1时不可以修改sk_rcvbuf的值,即如果锁了就不可以修改此值。
SOCK_BINDADDR_LOCK :宏值为4,sk_userlocks域在inet_bind函数中将第2位(最低位为0位)置位1,此位被置位后不可再调用inet_reset_saddr函数重新设置地址。
SOCK_BINDPORT_LOCK :宏值为8,sk_userlocks域在inet_bind函数中将第3位(最低位为0位)置位1,该位被置位后不可调用inet_put_port函数。
unsigned char sk_protocol
标示使用哪种协议,此域在inet_create中被初始化。
unsigned short sk_type
socket的类型,有7种类型,如下所示:
SOCK_STREAM:值为1,流套接字,提供双向连续且可信赖的数据流,TCP协议用此种类型。SOCK_DGRAM:值为2,数据报套接字,使用不连续不可信赖的数据包连接,UDP协议用此种类
型。
SOCK_RAW:值为3,原始套接字,一般的套接字是通过TCP才能和IP底层进行数据交换的,原始套接字可以直接穿过TCP层操作IP数据包,也就是说原始套接字是上层应用程序和IP层之间的通道。
SOCK_RDM:值为4,提供可信赖的数据包连接。
SOCK_SEQPACKET:值为5,顺序包套接字, 提供连续可信赖的数据包连接。
SOCK_DCCP:值为6,数据报阻塞控制协议套接字。
SOCK_PACKET:值为10,提供和网络驱动程序直接通信,Linux特有的方式。
还有一个特殊的宏,标示socket类型的上限值的宏SOCK_MAX,被定义为 (SOCK_PACKET + 1)。
Int sk_rcvbuf
以字节为单位的接收缓冲区的大小。
socket_lock_t sk_lock
sock的同步锁。
struct {
struct sk_buff *head;
struct sk_buff *tail;
} sk_backlog
sk_backlog链表中数据的处理的函数调用关系是:
tcp_recvmsg调用release_sock,release_sock调用__release_sock,__release_sock调用sk_backlog_rcv,而sk_backlog_rcv函数指针指向了tcp_v4_do_rcv,详情参见下面对sk_backlog_rcv的介绍,tcp_v4_do_rcv函数在TCP_ESTABLISHED状态时通过调用tcp_rcv_established函数实现数据处理并释放了节点。在TCP_LISTEN状态时会调用tcp_child_process。
sk_backlog链表中的数据被增加的函数调用关系是:
ip层接到数据包处理完后是通过ip_local_deliver函数把ip包递送到上层进行处理的(具体的Ip层及以下层是如何处理的在其他文档中讨论),ip_local_deliver函数调用ip_local_deliver_finish函数,ip_local_deliver_finish函数中通过全局的struct net_protocol的实例inet_protos[hash]取得struct net_protocol的指针。
inet_protos[hash]的handler域是一个函数指针指向了tcp_v4_rcv函数;系统中存在一个全局静态struct net_protocol结构的实例tcp_protocol,此实例的handler域被tcp_v4_rcv初始化,在inet_init函数中将此静态实例tcp_protocol通过inet_add_protocol付给了hash表结构的数组inet_protos,这样inet_protos[hash]->handler域就指向了tcp_v4_rcv。
tcp_v4_rcv函数在需要将数据放到sk_backlog对列时通过直接调用sk_add_backlog函数实现了将收到的数据增加到sk_backlog链表中,或者通过调用tcp_v4_do_rcv函数,tcp_v4_do_rcv在TCP_LISTEN状态时可能会调用tcp_child_process ,而tcp_child_process 再调用sk_add_backlog函数间接实现将收到的数据添加到sk_backlog链表中。
wait_queue_head_t *sk_sleep
等待队列,主要应用在客户端发起连接后等待连接完成,以及服务器端的accept函数等待新连接建立的完成。主要在rfcomm_sock_accept、sco_sock_accept、inet_wait_for_connect等函数中使用。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/100948/showart_2097388.html |
|