linux 网络实现的数据结构-连接

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;
}
变量分量初始化的值
inodei_sbsock_mnt->mnt_sb
i_modeS_IFSOCK|S_IRWXUGO
i_sock1
i_uidcurrent->fsuid
i_gidcurrent->fsgid
变量分量初始化的值
sock本身&inode->u.socket_i
inodeinode
fasync_listNULL
stateSS_UNCONNECTED
flags0
opsNULL
skNULL
fileNULL

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:

成员名称初始化内容
familyPF_INET
releaseinet_release
bindinet_bind
connectinet_stream_connect
socketpairsock_no_socketpair
acceptinet_accept
getnameinet_getname
polltcp_poll
ioctlinet_ioctl
listeninet_listen
shutdowninet_shutdown
setsockoptinet_setsockopt
getsockoptinet_getsockopt
sendmsginet_sendmsg
recvmsginet_recvmsg
mmapsock_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 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值