1: bsd socket
工作在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结构关联。这个部分在 sock_alloc原理分析,write与send疑问 中讲解过,不再重复。
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;
/* 连接状态。尤其 对tcp协议,他建立一个可靠的连接过程,实际上就是一个有穷状态机的变换过程,而有穷
* 状态机的状态就保存在这里
*/
volatile unsigned char state,
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;//出错队列
//操作函数集。后面会介绍这个结构。用于上下层衔接,比如对于tcp协议来说就是tcp_prot,对udp来说就是udp_prot。
struct proto *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 |