博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 网络实现的数据结构-连接
阅读量:2791 次
发布时间:2019-05-13

本文共 12468 字,大约阅读时间需要 41 分钟。

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结构关联。这个部分在  中讲解过,不再重复。

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/

你可能感兴趣的文章
Qt Quick 2 Extension Plugin 扩展插件
查看>>
qml中Control组件以及Style组件解析
查看>>
实现了一个类似微信好有列表的控件
查看>>
实现了一个可以滚动的文字控件
查看>>
自己重新定义的一个窗口控件
查看>>
关于typedef的用法
查看>>
CentOS6.5系统挂载NTFS分区的移动硬盘
查看>>
配置 yum 源的两种方法
查看>>
Unique Paths II
查看>>
Minimum Path Sum
查看>>
Maximum Subarray
查看>>
ACE Lock类介绍
查看>>
ACE_Task介绍
查看>>
mmap分析
查看>>
搞了个LAMP,没事也整理个问题集
查看>>
给你一段文章,Apache的日志分割和虚拟主机你还能不会?
查看>>
搞了Apache,怎么可能不搞搞Nginx呢?
查看>>
javascript调用微软CertEnroll实现CSP数字证书申请
查看>>
cookie实现本地数据存储
查看>>
Spring Boot添加DB2驱动
查看>>