最近在写网络编程方面的一些东西,然后遇到了关于传输上的小问题。由于之前有简单的看过一些TCP/IP详解的一些东西,所以索性就找了本《追踪LinuxTCP/IP代码运行》的书看了一上午,结果发现初次接触这些内核方面的东西,收获甚微。于是又在网上找相关类的大神博客,拿来拜读,虽然依然看的不是太明白,吸收的也不够好,但是我想以博客的形式把它记录下来,也希望能为我以后学这些东西开个好头吧
1.linux的网络协议栈的主要结构
(1)socket层
这层主要处理socket相关的东西,例如其各种结构的初始化等。每个socket在内核中以socket结构体的形式存在,它的结构体定义如下
socket结构体
struct socket
{
socket_stat state; //socket的状态
unsigned long flags; //socket的标志位
const struct proto_ops *pos //socket的函数操作表
struct fasync_struct *fasync_list //socket的异步唤醒队列
struct file *file; //与socket关联的文件指针
struct sock *sk; //代表具体协议内容的sock结构指针
wait_queue_head_t wait //用于等待队列
short type; //socket的类型
}
其中sock结构体封装了与具体协议相关的东西,它的结构体定义稍微有点大,所以这里我就不一一列出,只是简单的给大家介绍一下它定义的主要几个模块
(1)定义了与inet_timewait_sock共用的结构体sock_common,该结构体主要包含了地址族,连接状态,协议函数表等内容
(2)定义了各种和接收发送队列相关的数据以及队列
(3)用于记录以及提供控制的各种接收发送的数据
(2)INET socket层
该层是个可用于各种网络协议的接口,当用于TCP/IP
(3)TCP/UDP层
主要处理传输层的操作,传输层用struct inet_protocol和struct proto俩个结构表示
(4)IP层
处理网络层的操作,网络层用stuct packet_type结构的表示
(5)数据链路层和驱动程序
每一个网络设备都以struct net_device结构体表示
2.TCP/IP协议栈的一些代码的简单分析
(1)主要数据结构
struct msghdr
struct sk_buf
struct socket
struct sock
struct proto_ops
struct proto
不言而喻套接字层对应操作的就是socket,那么我们如何创建一个socket呢。接触过网络编程的大概都会知道疮疖一个套接字只需调用函数socket(),其实这个函数内部实现是非常复杂的,它会根据上述函数的参数创建一个socket实例(应该可以理解成对socket结构体的初始化),并创建一个套接字描述符,然后通过指针让这二者建立联系。其中初始化socket时,会根据不同的协议初始化出不同的函数操作表pos(见上面的结构体信息)。如果是TCP为inet_stream_ops,是UDP则为inet_dgram_ops,同时socket还通过调用sock中的相关操作完成从socket到sock层的传递初始化sock时还会初始化3个队列。recvive_queue(接收的数据包sk_buf链表队列),send_queue(需要发送数据包sk_buf的链表队列),back_queue(TCP三次握手成功的数据包队列)。还有将faimly初始化为inet类型,type为stream类型,sock_proto初始化为tcp_prot。
在一端进行write或send过程时,首先会把write缓冲区中的数据打包成msghdr的数据结构形式,然后调用sock_sendmsg把msghdr的数据发送至inet层(应运层与传输层的中间,提供各种协议的接口),然后msghdr的结构中的数据又被sk_buf结构所封装,此时的数据包就是个完全体了,可以挂在发送队列了
(2)linux的路由系统
主要保存了三种与路由相关的数据,第一种是在物理上和本机相连接的主机地址信息表,第二种是保存了在网络访问中判断一个网络地址应该走啥路由的数据表,第三种是最新使用过的查询路由地址的缓存地址数据表
FIB结构中保存了最重要的路由规则,通过其可以找到路由地址方法。系统中路由的手段一般为现在路由缓存中查找,如果能找到直接将对应的项作为路由规则,如果找不到,解根据FIB中的规则换算出来
数据链路层
前面提到的net_device硬件表对应于每一个网络接口设备。这个结构中包含了很多可以直接获取网卡信息的函数和变量,以及对网卡操作的函数,此类函数直接指向网卡驱动程序的入口,包括发送和接收帧到缓存区这些工作完成之后,便由netif_rx把缓存区中的帧组成sk_buf的形式挂到系统的系统的接收队列
2.启动过程
初始化进程主要:start—>kernel—>do_basic_setup—>sock_init—->do_initcalls
do_initcalls初始化的基本流程可以概述如下
(1)协议的初始化
(2)路由的初始化
(3)网络接口设备的初始化
3.网络连接
TCP连接通过如下函数
sockfd = socket(AF_INET,SOCK_STREAM,0);
connect(sockfd,&adress,sizeof(address))
在此函数的调用过程中主要发生了如下事情
(1)sys_socket系统调用,它又调用socket_creat()来创建一个满足socket函数参数的socket结构,而sock_creat()又会根据协议的不同调用不同的函数,对inet来说,它会调用inet_create函数,然后它还会调用其他的一系列的函数
(2)在系统初始化工作完成之后便会进行connect的工作,connect将一个和sockect关联的套接字描述符与一个远程的机器相关联,并调用各个协议自己对应的connect连接函数。TCP为inet_stream_connect
(3)inet_stream_connect会得到一个sk结构,这个sk结构描述了套接字的一些属性以及状态,对于TCP来说然后调用tcp_v4_connect函数
(4)tcp_v4_connect()又调用其他函数用于寻找合适的路由
4.连接的关闭
(1)关闭连接时由close调用sock_close函数
(2)sock_close()调用sock_release()来释放一些空间
(3)inet_release调用socket对应的协议的关闭函数,最后释放sk
5.发送数据的流程图
接收数据的流程图
大家如果看完我的学习笔记对哪有疑问的可以戳到人家的原文连接
http://blog.csdn.net/cz_hyf/article/details/602802