本文共 12468 字,大约阅读时间需要 41 分钟。
工作在bsd socket层用于连接的数据结构是socket{}。对bsd socket来说,传送的数据包类型也有多种。如下表:
数据包类型 | 宏定义 | 描述 |
流 | SOCK_STREAM | 流方式的数据,提供了可靠的双向数据流。主要用在tcp协议中 |
数据报 | SOCK_DGRAM | 不可靠的双向数据传输。主要是用在udp协议中 |
原始数据 | SOCK_RAW | 进程直接访问底层的协议,从而完成原始的不经过高层协议封装的数据包传输 |
...... | ...... | ...... |
//代表bsd socket层中的socket控制结构。在应用程序中使用的socket文件描述符与在bsd socket中的一个socket相对应struct socket{ socket_state state;//表示当前应用程序控制的套接字的状态内容。主要的状态有SS_CONNECTED和SS_UNCONNECTED,前者表示已连接,后者表示未连接。 unsigned long flags;//socket结构的控制信息,可以在应用层通过系统调用修改flags数据,从而改变bsd socket层对连接的控制情形 struct proto_ops *ops;//指向在bsd socket层上对不同地址族的操作函数集合,从而确定从bsd socekt 层到下层函数的接口。例如IPPROTO_TCP,为inet_stream_ops struct inode *inode;//在Linux中每一个文件都被描述成为一个inode。bsd socket也是一样。 struct fasync_struct *fasync_list; /* 异步处理的进程链表 */ struct file *file; /* 用于垃圾回收中指回的file结构的指针 */ struct sock *sk;//bsd socket层的下一层协议中用于引用网络传输数据和进行控制的结构指针。相互引用 wait_queue_head_t wait;//等待在这个socket结构上的任务列表。从socket结构到sock结构传递时,直接将wait传递给sock结构的睡眠成员。 short type;//数据包类型 unsigned char passcred;};
socket结构操作函数
这里介绍一些socket结构的操作函数
申请和释放
/*创建socket结构的通用过程,在这个函数内部会申请出这个socket结构对应的inode结构,并且从这个inode结构中得到socket结构的地址*/struct socket *sock_alloc(void){ struct inode * inode; struct socket * sock; inode = get_empty_inode(); if (!inode) return NULL; inode->i_sb = sock_mnt->mnt_sb; 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++;//保存了每一个CPU正在使用的套接字的数目。这里自增 return sock;}
变量 | 分量 | 初始化的值 |
inode | i_sb | sock_mnt->mnt_sb |
i_mode | S_IFSOCK|S_IRWXUGO | |
i_sock | 1 | |
i_uid | current->fsuid | |
i_gid | current->fsgid |
变量 | 分量 | 初始化的值 |
sock | 本身 | &inode->u.socket_i |
inode | inode | |
fasync_list | NULL | |
state | SS_UNCONNECTED | |
flags | 0 | |
ops | NULL | |
sk | NULL | |
file | NULL |
socket_file_ops操作函数集合
在inode中注册的针对socket结构操作的file_operations结构的操作函数集合是由socket_file_ops的成员解释的。从文件系统传递过来的操作都通过这个结构转换成对socket结构的操作函数。
static struct file_operations socket_file_ops = { llseek: sock_lseek, read: sock_read, write: sock_write, poll: sock_poll, 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};
在函数sock_map_fd中,将socket_file_ops和socket结构关联。这个部分在 中讲解过,不再重复。
2:inet socket: sock{}
sock结构定义,在inet socket数据结构中,管理数据包存放和调度的数据结构是sock。在inet socket层以下的网络层次上也会用到sock结构。
//rcv_saddr和num是指套接字绑定之后的地址和端口,也就是bind之后才做初始化struct sock { /* Socket demultiplex comparisons on incoming packets. */ __u32 daddr; /* 目的ipv4 地址 */ __u32 rcv_saddr; /* 源 ipv4地址 */ __u16 dport; /* 目的端口 */ unsigned short num; /* 源端口 */ int bound_dev_if; /* 如果不为0,那么这代表该sock结构对应的网络接口设备索引 */ /* Main hash linkage for various protocol lookup tables. */ struct sock *next;//同一系列的所有sock都连接在一起 struct sock **pprev; struct sock *bind_next; struct sock **bind_pprev; volatile unsigned char state, /* 连接状态。尤其 对tcp协议,他建立一个可靠的连接过程,实际上就是一个有穷状态机的变换过程,而有穷状态机的状态就保存在这里 */ zapped; /* In ax25 & ipx means not linked */ __u16 sport; /* 网络序的源端口 */ unsigned short family; /* 地址族 */ unsigned char reuse; /*如果设置了SO_REUSEADDR属性,为1*/ unsigned char shutdown;/* 用来标志在传输的过程中是否已经发送结束, */ atomic_t refcnt; /* sock结构的引用计数 */ socket_lock_t lock; /* 同步锁 */ int rcvbuf; /* 该sock结构允许最大的接收缓冲区大小,字节 */ wait_queue_head_t *sleep; /* 是等待在该sock上的进程队列,在socket结构中的等待队列成为wait */ struct dst_entry *dst_cache; /* 路由相关 */ rwlock_t dst_lock; atomic_t rmem_alloc; /* 当前申请了的接收缓冲区空间 */ struct sk_buff_head receive_queue; /* 等待接收的数据包队列头 */ atomic_t wmem_alloc; /* 当前申请了的发送缓冲区空间*/ struct sk_buff_head write_queue; /* 等待发送的数据包队列头 */ atomic_t omem_alloc; /* 可能用作其他用途的缓冲区大小 */ int wmem_queued; /* 队列大小 */ int forward_alloc; /* 为这个sock结构提前申请的数据区大小,这段数据去被其他缓冲区使用. */ __u32 saddr; /* 源地址 */ unsigned int allocation; /* Allocation mode */ int sndbuf; /* 该sock结构允许最大的接收缓冲区大小,字节 */ struct sock *prev; /* Not all are volatile, but some are, so we might as well say they all are. * XXX Make this a flag word -DaveM */ volatile char dead, done, urginline, keepopen, linger, destroy, no_check, broadcast, bsdism; unsigned char debug; unsigned char rcvtstamp; unsigned char userlocks; int proc;//在接收带外数据的时候,需要给某进程发送信号表示数据已经收到。这个进程的信号记录在此 unsigned long lingertime; int hashent; struct sock *pair;//socketpair系统调用时会设置,调用unix_stream_ops的unix_socketpair函数相互引用 /* 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; } backlog; rwlock_t callback_lock; /* Error queue, rarely used. */ struct sk_buff_head error_queue;//出错队列 struct proto *prot;//操作函数集。后面会介绍这个结构。用于上下层衔接,比如对于tcp协议来说就是tcp_prot,对udp来说就是udp_prot。#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) union { struct ipv6_pinfo af_inet6; } net_pinfo;//ipv6相关#endif union { struct tcp_opt af_tcp;#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE) struct raw_opt tp_raw4;#endif#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct raw6_opt tp_raw;#endif /* CONFIG_IPV6 */#if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE) struct spx_opt af_spx;#endif /* CONFIG_SPX */ } tp_pinfo;//保存的是一些和协议相关的特定信息。比如tcp,tcp_opt结构的af_tcp保存了足够多的tcp信息 int err, err_soft; /* Soft holds errors that don't cause failure but are the cause of a persistent failure not just 'timed out' */ unsigned short ack_backlog; unsigned short max_ack_backlog; __u32 priority; unsigned short type; unsigned char localroute; /* Route locally only */ unsigned char protocol; struct ucred peercred; int rcvlowat; long rcvtimeo; long sndtimeo;#ifdef CONFIG_FILTER /* Socket Filtering Instructions */ struct sk_filter *filter;#endif /* CONFIG_FILTER */ /* This is where all the private (optional) areas that don't * overlap will eventually live. */ union { void *destruct_hook; struct unix_opt af_unix;#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE) struct inet_opt af_inet;#endif#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) struct atalk_sock af_at;#endif#if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) struct ipx_opt af_ipx;#endif#if defined (CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE) struct dn_scp dn;#endif#if defined (CONFIG_PACKET) || defined(CONFIG_PACKET_MODULE) struct packet_opt *af_packet;#endif#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE) x25_cb *x25;#endif#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) ax25_cb *ax25;#endif#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) nr_cb *nr;#endif#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE) rose_cb *rose;#endif#if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE) struct pppox_opt *pppox;#endif#ifdef CONFIG_NETLINK struct netlink_opt *af_netlink;#endif#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) struct econet_opt *af_econet;#endif#if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE) struct atm_vcc *af_atm;#endif#if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE) struct irda_sock *irda;#endif } protinfo; //其他协议,非tcp协议的私有数据保存在此 /* This part is used for the timeout functions. */ struct timer_list timer; /* This is the sock cleanup timer. */ struct timeval stamp; /* Identd and reporting IO signals */ struct socket *socket;//引用上层的socket结构 /* RPC layer private data */ void *user_data; /* 回调函数。在对inet socket做出处理的时候,适当的情况下调用这些函数来完成后续工作,比如三次握手的第三次握手结束之际,tcp_child_process检查state如果是TCP_SYN_RECV并且状态已经改变,执行data_ready回调*/ void (*state_change)(struct sock *sk); void (*data_ready)(struct sock *sk,int bytes); void (*write_space)(struct sock *sk); void (*error_report)(struct sock *sk); int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); void (*destruct)(struct sock *sk);};
sock结构操作函数
申请和释放
struct sock *sk_alloc(int family, int priority, int zero_it){ struct sock *sk = kmem_cache_alloc(sk_cachep, priority); if(sk && zero_it) { memset(sk, 0, sizeof(struct sock)); sk->family = family; sock_lock_init(sk); } return sk;}
比较简单,就不分析了。
void sk_free(struct sock *sk){#ifdef CONFIG_FILTER struct sk_filter *filter;#endif if (sk->destruct)//可能需要特殊处理 sk->destruct(sk);#ifdef CONFIG_FILTER filter = sk->filter;//如果配置了过滤器,在这里释放 if (filter) { sk_filter_release(sk, filter); sk->filter = NULL; }#endif if (atomic_read(&sk->omem_alloc))//如果不为0,打印告警信息,可能存在内存泄漏 printk(KERN_DEBUG "sk_free: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc)); kmem_cache_free(sk_cachep, sk);}
协议操作集合
和连接相关的用于操作的集合是proto_ops和proto结构。都是函数指针的集合。
bsd:
struct proto_ops { int family; int (*release) (struct socket *sock); int (*bind) (struct socket *sock, struct sockaddr *umyaddr, int sockaddr_len); int (*connect) (struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags); int (*socketpair) (struct socket *sock1, struct socket *sock2); int (*accept) (struct socket *sock, struct socket *newsock, int flags); int (*getname) (struct socket *sock, struct sockaddr *uaddr, int *usockaddr_len, int peer); unsigned int (*poll) (struct file *file, struct socket *sock, struct poll_table_struct *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg); int (*listen) (struct socket *sock, int len); int (*shutdown) (struct socket *sock, int flags); int (*setsockopt) (struct socket *sock, int level, int optname, char *optval, int optlen); int (*getsockopt) (struct socket *sock, int level, int optname, char *optval, int *optlen); int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); int (*mmap) (struct file *file, struct socket *sock, struct vm_area_struct * vma);};
inet_stream_ops:
成员名称 | 初始化内容 |
family | PF_INET |
release | inet_release |
bind | inet_bind |
connect | inet_stream_connect |
socketpair | sock_no_socketpair |
accept | inet_accept |
getname | inet_getname |
poll | tcp_poll |
ioctl | inet_ioctl |
listen | inet_listen |
shutdown | inet_shutdown |
setsockopt | inet_setsockopt |
getsockopt | inet_getsockopt |
sendmsg | inet_sendmsg |
recvmsg | inet_recvmsg |
mmap | sock_no_mmap |
inet socket proto
struct proto { void (*close)(struct sock *sk, long timeout);//在关闭连接之前一些善后操作,比如tcp协议,要完成的任务就是发送一个必要的ack信号和fin信号表示传输结束 int (*connect)(struct sock *sk, struct sockaddr *uaddr, int addr_len);//面向连接和无连接的协议来说,实现是不一样的。对面对无连接的协议来说,每次都需要直接指定发送的目的地址,而面对连接的协议,只需要指定一次目的地址就行了。 int (*disconnect)(struct sock *sk, int flags); struct sock * (*accept) (struct sock *sk, int flags, int *err);//tcp协议需要实现 int (*ioctl)(struct sock *sk, int cmd, unsigned long arg);//设置一些属性 int (*init)(struct sock *sk);//初始化sock结构 int (*destroy)(struct sock *sk);//销毁sock结构 void (*shutdown)(struct sock *sk, int how);//关闭连接 int (*setsockopt)(struct sock *sk, int level, //设置和获取选项 int optname, char *optval, int optlen); int (*getsockopt)(struct sock *sk, int level, int optname, char *optval, int *option); int (*sendmsg)(struct sock *sk, struct msghdr *msg, int len);//发送和接收数据的函数 int (*recvmsg)(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags, int *addr_len); int (*bind)(struct sock *sk, struct sockaddr *uaddr, int addr_len);//将一个sock结构和目的地址端口绑定 int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb);//用来从backlog队列中接收数据 /* Keeping track of sk's, looking them up, and port selection methods. */ void (*hash)(struct sock *sk);//用于将sock结构放入hash表的函数 void (*unhash)(struct sock *sk);//逆操作 int (*get_port)(struct sock *sk, unsigned short snum);//给指定的sock结构获取一个可以用的本地端口,如果snum不为0,尝试使用之,否则会获取一个未被占用的端口 char name[32];//调试用的 struct { int inuse; u8 __pad[SMP_CACHE_BYTES - sizeof(int)]; } stats[NR_CPUS];//snmp使用的统计信息};
tcp_prot
成员名称 | 初始化内容 |
name | "TCP" |
close | tcp_close |
connect | tcp_v4_connect |
disconnect | tcp_disconnect |
accept | tcp_accept |
ioctl | tcp_ioctl |
init | tcp_v4_init_sock |
destroy | tcp_v4_destroy_sock |
shutdown | tcp_shutdown |
setsockopt | tcp_setsockopt |
getsockopt | tcp_getsockopt |
sendmsg | tcp_sendmsg |
recvmsg | tcp_recvmsg |
backlog_rcv | tcp_v4_do_rcv |
hash | tcp_v4_hash |
unhash | tcp_unhash |
get_port | tcp_v4_get_port |
转载地址:http://nvtmd.baihongyu.com/