⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 -

📁 linux informations
💻
📖 第 1 页 / 共 3 页
字号:
    INET socket层支持包括TCP/IP协议在内的internet地址族。如前所述,这些协议是分层的,一个协议使用另一个协议的服务。Linux的TCP/IP代码和数据结构反映了这一分层模型。它与BSD socket层的接口要通过一系列Internet地址族socket操作,这一操作是在网络初始化时就已经注册到BSD socket层的。这些都与其它已注册的地址族一起保存在 pops 向量中。BSD socket层从已注册的INET proto_ops 数据结构中调用INET层 socket支持例程来为它执行工作。例如,一个地址族为INET的BSD socket建立请求,将用到下层的INET socket的建立函数。在这些操作中,BSD socket层把用来描述BSD socket的 socket 结构传构到INET层。为了不把BSD socket 与TCP/IP的特定信息搞混,INET socket层使用它自己的数据结构,sock ,它与BSD socket 结构相连。这一联接关系可以从图  10.3 中看出。它用BSD socket的 data 指针来连接 sock 结构与BSD socket结构。这意味着后来的INET socket调用能够很容易地重新找到 sock 结构。 sock 结构的协议操作指针也在初始化时建立,它依赖与被请求的协议。如果请求的是TCP,那么 sock 结构的协议操作指针将指向TCP连接所必需的TCP协议操作集。 


10.4.1  建立BSD socket
    系统建立一个新的socket时,通过标识符来确定它的地址族,socket类型和协议。 

    首先,从 pops 向量中搜索与被请求的地址族相匹配的地址族。它可能是一个作为核心模块来实现的一个特定的地址族,这样,在其能继续工作前, kerneld 守护进程必须加载这一模块。分配一个新的 socket 结构来代表BSD socket。实际上 socket 结构是 VFS inode 结构的一部分,分配一个socket实际上就是分配一个 VFS inode 。除非你认为socket操作能和普通的文件操作一样,否则会觉得这好象很奇怪。所有的文件用VFS inode结构来表示,为了支持文件操作,BSD socket必须也用 VFS inode 来表示。 

    最新建立的 BSD socket 结构包含一个指向地址族特定socket例程的指针,可以用来从 pops 向量中找到 proto_ops 结构。它的类型被设置成被请求的socket类型:SOCK_STREAM,SOCK_DGRAM等等之一。调用地址族特定创建例程使用保存在 proto_ops 结构中的地址。 

    从当前过程 fd 向量中分配一个自由的文件描述符,对 file 结构所指向的进行初始化。包括将文件操作指针设置为指向由BSD socket接口支持的BSD socket文件操作集。任何操作将被引到socket接口,通过调用它的地址族操作例程将它们传到支持的地址族。 

10.4.2  将地址与INET BSD socket绑定
    为了能监听输入的internet连接请求,每个服务器必须建立一个INET BSD socket,并将地址与其绑定。绑定操作主要在INET socket层内处理,下面的TCP和UDP协议层提供一些支持。与一个地址绑定了的socket不能用来进行任何其它的通讯工作,也就是说:socket的状态必须是 TCP_CLOSE 。 sockaddr 结构包含了与一个任意的端口号绑定的IP地址。通常绑定的IP地址已经分配给了一个网络设备,该设备支持INET地址族且其接口是可用的。可以在系统中用ifconfig命令来查看哪一个网络接口是当前激活的。IP地址也可以是广播地址,全1或全0。这是些特定的地址,用以表示发送给任何人3。如果机器充当一个透明的代理或防火墙,则IP地址可被指定为任一个IP地址,但只有有超级用户权限的进程能绑定到任何一个IP地址。绑定的IP地址被存在sock结构中的 recv_addr 和 saddr 字段。端口号是可选的,如果没有指定,将任意指定一个。按惯例,小于1024的端口号不能被没有超级用户权限的进程使用。如果下层网络没有分配端口号,则分配一个大于1024的端口号。 

    下层网络设备接收的包必须由经正确的INET和BSD socket才能被处理。因此,UDP和TCP维护了一些hash表用来在输入IP消息内查找地址并将它们导向正确的 socket/sock 对。TCP是一个面向连接的协议,因而涉及处理TCP包的信息比用于处理UDP包的信息多。 

UDP维护着一张已分配UDP端口表, udp_hash 表。由指向 sock 数据结构的指针组成,通过一个基于端口号的hash函数来索引。UDPhash表比允许的端口号的数目小得多(udp_hash 为128 或者说是 UDP_HTABLE_SIZE )表中的一些项指向一个 sock 结构链,该链用每个 sock 结构中的 next 指针来将每个 sock 连接起来。 

    TCP是十分复杂的,它包括几个hash表。但实际上TCP在绑定操作时没有将 sock 结构与其hash表绑定,它仅仅检查被请求的端口号当前没被使用。 sock 结构是在 listen 操作时被加入TCP的hash表的。 

复习提要: What about the route entered? 


10.4.3  在INET BSD Socket上建立连接
    建立一个socket,如果没有用它来监听连入请求,那么就能用它来发连出请求。对于面向无连接的协议如UDP来说,这一socket操作并不做许多事,但对于面向连接的协议如TCP来说,这一操作包括了在两个应用间建立一个虚连接。 
    一个连出连接操作只能由一个在正确状态下的INET BSD socket来完成;换句话说,socket不能是已建立连接的,并且有被用来监听连入连接。这意味着BSD socket 结构必须是 SS_UNCONNECTED 状态。UDP协议没有在两个应用间建立虚连接,任何发出的消 息都是数据报,这些消息可能到达也可能不到达目的地。但它不支持BSD socket的 connect 操作。建立在UDP的INET BSD socket上的连接操作简单地设置远程应用的地址:IP地址和IP端口号。另外,它还设置路由表入口的cache以便这一BSD socket在发用UDP包时不用再次查询路由数据库(除非这一路由已经无效)。INET sock 结构中的 ip_route_cache 指针指向路由缓存信息。如果没有给出地址信息,缓存的路由和IP地址信息将自动地被用来发送消息。UDP将 sock 的状态改为 TCP_ESTABLISHED 。 

对于基于TCP BSD socket的连接操作,TCP必须建立一个包括连接信息的TCP消息,并将它送到目的IP。TCP消息包含与连接有关的信息,一个唯一标识的消息开始顺序号,通过初始化主机来管理的消息大小的最大值,及发送与接收窗口大小等等。在TCP内,所有的消息都是编号的,初始的顺序号被用来作为第一消息号。Linux选用一个合理的随机值来避免恶意协议冲突。每一从TCP连接的一端成功地传到另一端的消息要确认其已经正确到达。未确认的消息将被重传。发送与接收窗口的大小是第一个确认到达之前消息的个数。消息尺寸的最大值与网络设备有关,它们在初始化请求的最后时刻确定下来。如果接收端的网络设备的消息尺寸最大值更小,则连接将以小的一端为准。应用程序发出连接请求后必须等待目标应用程序的接受或拒绝连接的响应。TCP sock 期望着一个输入消息,它被加入 tcp_listening_hash 以便输入TCP消息能被指向这一 sock 结构。TCP同时也开始计时,当目标应用没有响应请求,则连出连接请求超时。 

10.4.4  监听 INET BSD Socket
    socket与地址绑定后,能监听指定地址的连入连接请求。一个网络应用程序能监听socket而不用先将地址 与之绑定;在这个例子中,INET socket层找到一个未用的端口号(对这一协议)并自动将它与socket绑定。 监听socket函数将socket状态设成 TCP_LISTEN ,并做其它连入连接所需要的工作。

    对于UDP sockets,改变socket的状态就足够了,而TCP现在加了socket的 sock 数据结构到两个hash表中并激活, tcp_bound_hash 表和 tcp_listening_hash 表。这两个表都通过一个基于IP端口号的hash函数来索引。

    无论何时,一个激活的监听socket接收一个连入的TCP连接请求,TCP都要建立一个新的 sock 结构来描述它。最终接收时,这个 sock 结构将成为TCP连接的底层。它也复制包含连接请求的 sk_buff ,并将它放到监听 sock 结构的 receive_queue 中排队。复制的 sk_buff 包含一个指向新建立的 sock 结构的指针。 

10.4.5  接收连接请求
    UDP不支持连接的概念,接收INET socket连接请求只适用于TCP协议,一个监听socket接收操作从原始的监听socket中复制新的socket结构。接收操作透过支持的协议层,本例是INET,来接收任何连入连接请求。如果下层协议,如UDP,不支持连接,INET协议层接收操作将失败。否则接收操作透过真实协议层,本例是TCP。接收操作可以是阻塞或非阻塞。在非阻塞情况下,如果没有连入连接可接收,则接收操作失败,新建的socket 结构被废弃。在阻塞情况下,网络应用程序执行接收操作将加上一个等待队列并将之挂起,直到接收到TCP连接请求。当接收一个连接请求后,包含请求的 sk_buff 被废弃,并且 sock 数据结构返回到INET socket层,在那与一个新的更早建立的socket结构连接。新socket文件描述符(fd)号返回给网络应用程序,然后,应用程序就能在socket操作中将这一文件描述符用于新建立的INET BSD socket。 

10.5  IP层
10.5.1  Socket 缓存
    每一层协议用另外层提供的服务,这样使用多层网络协议会有一个问题:每个协议都要在传送数据时都要 加上协议头和协议尾,而数据到达时又要将之去掉。这样,在不同的协议间要有数据缓存,每一层需要知道特 定协议的头和尾放在哪个位置。一个解决办法就是在每一层中都拷贝缓存,但这样做效率就很低。Linux用 socket缓存或者说 sk_buffs 来在协议层与网络设备驱动之间交换数据。 sk_buffs 包括指针和字段长度,这样每 个协议层就可以通过标准的函数或“方法”来操作应用程序数据。 





图 10.4: Socket 缓存 (sk_buff) 

    图  10.4 显示了 sk_buff 数据结构;每个 sk_buff 有一个数据块与之相连。 sk_buff 有四个指针,这些指针 用来操作和管理socket缓存的数据: 

head 
指向内存中数据区的开头。这一指针在 sk_buff 和其相关的数据块分配时就固定了。 
data 
指向当前协议数据的开头。这一指针是随当前拥有 sk_buff 的是哪个协议层而变化的。 
tail 
指向当前协议数据的结尾。同样,这一指针也是随当前拥有 sk_buff 的是哪个协议层而变化的。 
end 
指向内存中数据区的结尾。这一指针在 sk_buff 和其相关的数据块分配时固定。 
     len 和 truesize 这两个字段分别用来描述当前协议包长度和数据缓存总体长度。 sk_buff 处理代码提供标准的操作来向应用程序增加和移除协议头和协议尾。这就可以安全地操作 sk_buff 中的 data , tail 和 len 字段。 

push 
它把 data 指针指向数据区的开始并增加 len 。用于在要传输的数据开始处增加协议头。 

pull 
它把 data 指针从数据区的开始处移到数据区的结尾处,并减小 len 。用于在已接收的数据开始处移除协议头。 

put 
它把 tail 指针指向数据区的结尾处,并增加 len 。用于在要传输的数据结尾处增加数据或协议信息。 

trim 
它把 tail 指针指向数据区的开始处,并减小 len 。用于在已接收的数据尾移除数据或协议信息。 

    sk_buff 结构还包含了用于一些指针,用于在处理过程中存入 sk_buff 的双连接环路列表。通用sk_buff例 程可以将 sk_buff 加入到这些列表的前面或后面,也可以删除它们。 

10.5.2  接收IP包
    第  dd-chapter 章描述了Linux的网络设备是如何置入内核并初始化的。一系列 device 数据结构在 dev_base 表中相互连接起来。每个 device 结构描述了它的设备并提供回调例程,当需要网络驱动来执行工作时,网络协议层调用这些例程。这些函数与传输的数据及网络设备地址紧密相关。当一个网络设备从网上接收包时,它必须将接收的数据转换成 sk_buff 结构。这些 sk_buff 则被网络驱动加入到了 backlog 队列中。

    如果 backlog 队列太长,则丢弃接收的 sk_buff。准备好要运行时,网络底层将被设置标志。

    当网络底层按计划开始运行后,处理 backlog 队列之前,任何等待着被传输的网络包都由它来处理。 sk_buff 决定哪些层处理被接收的包。 

    Linux网络层初始化时,每一协议通过将 packet_type 结构加入到 ptype_all列表或ptype_base hash表中来 注册它自己。packet_type 结构包含了协议类型,一个指向网络设备的指针,一个指向协议的接收数据处理例程的指针,最后还包括一个指向列表链或hash链中下一个 packet_type 结构的指针。ptype_all 链用于监听从网络设备上接收的所有包,通常不使用它。ptype_base hash表是被协议标识符弄乱的,用于决定哪个协议将接收传入的网络包。网络底层通过两个表中的一个或多个 packet_type 项来匹配传入 sk_buff 的协议类型。协议可以和多于一个的项相匹配,如在监听网上所有的传输时要复制多个 sk_buff 。 sk_buff 将通过被匹配协议处理例程。 

10.5.3  发送IP包

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -