博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux TCP/IP协议栈剖析【体系结构篇】
阅读量:4049 次
发布时间:2019-05-25

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

最近在看linux内核代码,学习之余记点笔记。但是,目前整个linux源码文件大小是360M,相当于100个哈利波特全集-_-,看完的都是神仙了。所以我只准备粗略地看下它的TCP/IP协议栈,然后记点心得。

嗯,我研究的内核版本是目前最新的,linux-2.6.33.1,其实应该都大同小异。学习源码时,首先应该把它的整体脉络理清楚,然后再局部细看,这是最简捷的。本文也是简洁的归纳一下。

在linux下,socket都挂接到虚拟文件系统(VFS)上,所以可以把它当做文件来操作,如write()与read()都可以对它使用。

当我们调用fd = socket()操作时,传递过程从上到下如下所示:

VFS层:file

运输层:socket

网络层:sock

嗯,相信大家都知道了吧,VFS层上面就是应用层了,每本计算机网络相关书籍总是会先讲这几个层级结构。其中file, socket, sock是对应层次的一个内核结构,file涉及到虚拟文件系统,所以不予剖析了。

我们先看看socket结构的定义:

struct socket {	socket_state		state;	kmemcheck_bitfield_begin(type);	short			type;	kmemcheck_bitfield_end(type);	unsigned long		flags;	/*	 * Please keep fasync_list & wait fields in the same cache line	 */	struct fasync_struct	*fasync_list;	wait_queue_head_t	wait;	struct file		*file;	struct sock		*sk;	const struct proto_ops	*ops;};

我们只关心最后3个结构成员,file就是对应上面的VFS层,sk则是下面的网络层,而ops则指向一个函数指针集合,对应于该运输层的操作,实际上它可指向3个集合:inet_stream_ops,  inet_dgram_ops,  inet_sockraw_ops。还记得我们创建socket时需要设定的type参数吗,SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,相应的参数使套接字在初始化时让ops指向对应的函数指针集合。

下面就是这个函数指针集合的定义:

struct proto_ops {	int		family;	struct module	*owner;	int		(*release)   (struct socket *sock);	int		(*bind)	     (struct socket *sock,				      struct sockaddr *myaddr,				      int sockaddr_len);	int		(*connect)   (struct socket *sock,				      struct sockaddr *vaddr,				      int sockaddr_len, int flags);	int		(*accept)    (struct socket *sock,				      struct socket *newsock, int flags);	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 __user *optval, unsigned int optlen);	int		(*getsockopt)(struct socket *sock, int level,				      int optname, char __user *optval, int __user *optlen);	int		(*sendmsg)   (struct kiocb *iocb, struct socket *sock,				      struct msghdr *m, size_t total_len);	int		(*recvmsg)   (struct kiocb *iocb, struct socket *sock,				      struct msghdr *m, size_t total_len,				      int flags);        。。。。。。。
};

是不是都似曾相识呢,对,上面的都是套接字的常用操作。

最后,我们再看看网络层,sock结构,只列举了我觉得有用的成员,这个结构很长。

struct sock {	struct sock_common	__sk_common;	struct sk_buff_head	sk_receive_queue;	struct sk_buff_head	sk_write_queue;	struct socket		*sk_socket;	void			*sk_user_data;	struct sk_buff		*sk_send_head;	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);};

加下划线的两个函数指针,用于与更底层交互,当网卡有数据可读可写时用于回调。继续钻下去的话还会很深。最重要的是,它的头部是一个sock_common 结构。嗯,这相当于一个面向对象的设计,sock_common就类似是一个基类,通过强制转换可以转化。还要关注下sk_buff_head结构,他是socket内部使用的缓冲区,链表形式,以后我再写下它。

sock_common结构定义如下:同样只是简单列举一些重要的。

struct sock_common {	union {		struct hlist_node	skc_node;		struct hlist_nulls_node skc_nulls_node;	};	atomic_t		skc_refcnt;	int			skc_tx_queue_mapping;	unsigned short		skc_family;	volatile unsigned char	skc_state;	unsigned char		skc_reuse;	int			skc_bound_dev_if;	struct proto		*skc_prot;};
注意skc_prot也指向一个函数指针集合,对应于网络层的各种操作。但是据我观察,按理说tcp_recv应该在socket层调用,而实际上该tcp_recv却定义在sock层,socket层只是简单跳转一下,由skc_prot调用,我想可能是为了方便tcp协议的实现吧。

 

好了,大概结构就是这样的吧。。可以看到,就算是C语言,也运用了很多面向对象的思想。还有很抱歉,我本来准备画图说明的,结果还是惰性使然,就没画了。本来体系结构就是个很模糊的东西,关于数据包的接收与传送,以及他们在这体系结构间的传递,下篇再讲解。

转载地址:http://zrbci.baihongyu.com/

你可能感兴趣的文章
WPF UI&控件免费开源库
查看>>
QT打开项目提示no valid settings file could be found
查看>>
Win10+VS+ESP32环境搭建
查看>>
Ubuntu+win10远程桌面
查看>>
flutter-实现圆角带边框的view(android无效)
查看>>
android 代码实现圆角
查看>>
flutter-解析json
查看>>
android中shader的使用
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>
drat中构造方法
查看>>
JavaScript的一些基础-数据类型
查看>>
JavaScript基础知识(2)
查看>>
转载一个webview开车指南以及实际项目中的使用
查看>>
android中对于非属性动画的整理
查看>>
一个简单的TabLayout的使用
查看>>
ReactNative使用Redux例子
查看>>
Promise的基本使用
查看>>
coursesa课程 Python 3 programming 统计文件有多少单词
查看>>
coursesa课程 Python 3 programming 输出每一行句子的第三个单词
查看>>
Returning a value from a function
查看>>