协议层使用协议控制块(PCB)存放各UDP和TCP插口所要求的多个信息片。Internet协议维护Internet协议控制块

(internet protocol control block)和TCP控制块(TCP control block)。由于UDP是无连接的。所以一个端结点须要的

全部信息都在Internet PCB中找到,不存在UDP控制块。

Internet PCB含有全部UDP和TCP端结点共同拥有的信息:外部和本地IP地址、外部和本地端号、IP首部原型、该端结点使用的

IP选项以及一个指向该端结点目的地址选路表入口的指针。TCP控制块包括了TCP为各连接维护的全部结点信息:两个方向

的序号、窗体大小、重传次数等等。

下图总结了协议控制块以及它们与file和socket结构之间的关系。

图中有几个要点要考虑:

1.当socket或accept创建一个插口后,插口层生成一个file结构和一个socket结构。文件类型是DTYPE_SOCKET,UDP端结点

的插口类型是SOCK_DGRAM,TCP端结点插口类型是SOCK_STREAM。

2.然后调用协议层。UDP创建一个Internet PCB(一个inpcb结构),并把它链接到socket结构上:so_pcb成员指向inpcb结构,

inp_socket成员指向socket结构。

3.TCP做相同的工作,也创建它自己的控制块(一个inpcb结构),并用指针inp_ppcb和t_inpcb把它链接到inpcb上。在两个

UDP inpcb中,inp_ppcb成员是一个空指针。由于UDP不负责维护它自己的控制块。

4.我们显示的其它四个inpcb结构的成员,从inp_faddr到inp_lport,形成了该端结点的插口对:外部IP地址和端口号,以及

本地IP地址和port号。

5.UDP和TCP用指针inp_next和inp_prev维护一个全部Internet PCB的双向链表。他们在表头分配一个全局inpcb(命名为udb

和tcb)。在该结构中使用三个成员:下一个和前一个指针,以及本地port号。后一个成员中包括了该协议使用的下一个暂时

port号。

Internet PCB是一个传输层数据结构。TCP、UDP和原始IP使用它,可是IP、ICMP或IGMP不用它。

1.inpcb的结构

下图是inpcb结构的定义。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

inp_next和inp_prev为UDP和TCP的全部PCB形成一个双向链表。另外。每一个PCB都有一个指向协议链表表头的指针(inp_head)。

对UDP表上的PCB,inp_head总是指向udb。

inp_faddr、inp_fport、inp_laddr和inp_lport。包括了这个IP端结点的插口对:外部IP地址和端口号,以及本地IP地址和

port号。PCB中以网络字节序维护这四个值。

inp_socket是一个指向该PCB的socket结构的指针。inp_ppcb是一个指针,它指向这个PCB的可选运输层专用控制块。inp_ppcb

和TCP一起指向相应的tcpcb,而UDP不使用它。

假设ip有一个到外部地址的路由,则它被保存在ipp_route入口处。

当收到一个ICMP重定向报文时。将扫描全部Internet PCB,

找到那些外部IP地址和重定向IP地址匹配的PCB,将其inp_route入口标记成无效。当再次将该PCB用于输出时,迫使IP又一次找

一条到该外部地址的新路由。

inp_flag成员存放几个标志。下图显示了各标志。



PCB中维护一个IP首部的备份,但它仅仅使用当中的两个成员,TOS和TTL。TOS被初始化成0,TTL被运输层初始化。TCP和UDP都

把TTL默认值设为64。

进程能够用IP_TOS或IP_TTL插口选项改变这些默认值。新的记录在inpcb-inp_ip结构中。

以后,TCP和

UDP在发送IP数据报时,却把该结构用作原型IP首部。

进程也能够用IP_OPTIONS插口选项设置外出数据报的IP选项,函数ip_pcbopts把调用方选项的备份存放在一个mbuf中,

inp_option成员是一个指向该mbuf的指针。每次TCP和UDP调用ip_output函数时,就把一个指向这些IP首部的指针传给IP,IP

将其插到出去的IP数据报中。类似地,inp_moptions成员是一个指向用户IP多播选项备份的指针。

2.in_pcballoc和in_pcbdetach函数

在创建插口时,TCP、UDP和原始IP会分配一个InternetPCB。

通过公布PRU_ATTACH请求后,调用in_pcballoc函数实现:函数

调用内核的内存分配器,分配一个inpcb,然后进行初始化,最后被加到协议的双向链表上。

在公布PRU_DETACH请求后,释放一个Internet PCB,这是在关闭插口时发生的。通过把PCB从协议的双向链表中移走,该PCB

使用的内存被返回给内核。

3.绑定、连接和分用

1.绑定本地IP地址和port号。

下图是进程在调用bind时能够指定的本地IP地址和本地port号的六种组合。



假设客户程序试图绑定一个已经被其它插口使用的本地port时会发生什么情况。默认情况下,假设一个port已经被使用,进程

是不能绑定它的。假设发生这样的情况,则返回EADDRINUSE差错(地址正在被使用)。正在被使用的定义非常easy。就是仅仅要存在

一个PCB,就把该port作为它的本地port。“正在被使用”的概念是相对于绑定协议的:TCP或UDP。由于TCPport号与UDPport号

无关。

Net/3同意进程指定一下两个插口选项来改变这个默认行为。

SO_REUSEADDR:

SO_REUSEADDR同意启动一个监听server并捆绑其众所周知port。即使曾经建立的将此port用做他们的本地port的连接仍存在。

这一般是重新启动监听server时出现,若不设置此选项,则bind时将出错。

SO_REUSEADDR同意在同一port上启动同一server的多个实例。仅仅要每一个实例捆绑一个不同的本地IP地址就可以。对于TCP,我

们根本不可能启动捆绑同样IP地址和同样port号的多个server。

SO_REUSEADDR同意单个进程捆绑同一port到多个套接口上。仅仅要每一个捆绑指定不同的本地IP地址就可以。这一般不用于TCP服

务器。

SO_REUSEADDR同意全然反复的捆绑:当一个IP地址和port绑定到某个套接口上时,还同意此IP地址和port捆绑到还有一个套接

口上。一般来说,这个特性仅在支持多播的系统上才有。并且仅仅对UDP套接口而言(TCP不支持多播)。

SO_REUSEPORT:

同意进程重用IP地址和port号,可是包括第一个在内的各个IP地址和port号,必须指定这个插口选项。

2.连接一个UDP插口

我们通常把connect系统调用和TCP客户联系起来。可是UDP客户或UDPserver也能够可能调用connect,为插口指定外部IP地址

和外部port号。这就限制插口必须仅仅与某个特定对方交换UDP数据报。

当连接UDP插口时,会有一个副作用:本地IP地址。假设在调用bind是没有指定。会自己主动被connect设置。它被设成由IP选路指定

对方所选择的本地接口地址。

下图显示了UDP插口的三种不同状态,以及函数为终止各状态调用的伪代码。

前三个状态叫做已连接的UDP插口,后两个叫做未连接的UDP插口,两个没有连接上的UDP插口的差别在于,第一个具有

一个全然指定的本地地址,而第二个具有一个通配本地IP地址。

3.分用TCP接收和IP数据报

下图显示了主机上三个Telnetserver的状态。前两个插口处于LISTEN状态,等待进入的连接请求。

第三个连接到IP地址是

140.252.1.11的主机上的port1500。第一个监听插口处理在接口140.252.1.29上到达的连接请求。第二个监听将处理全部

其它接口。

当TCP收到一个目的port是23的报文段时,它调用in_pcblookup,搜索它的整个Internet PCB表。找到一个匹配。它由优先

权。由于它的通配数最少。为了确定通配匹配数,我们仅仅考虑本地和外部IP地址,不考虑外部port号。本地port号必须匹配。

否则我们甚至不考虑PCB。通配数能够是0,1,2。

4.分用UDP接收的IP数据报

UDP数据报的交付比我们刚才研究的TCP样例要复杂得多,由于能够把UDP数据报发送到一个广播或多播地址。Net/3的规则

是:

1)把目的地是广播IP地址或多播IP地址的到达UDP数据报交付给全部匹配的插口。

这里没有最好的匹配的概念。

2)把目的地是单播IP地址的到达UDP数据报仅仅交付给一个匹配的插口,就是具有最小匹配数的插口。假设有多个插口具有同样

最小通配匹配数,那么详细由哪个插口来接收到达数据报依赖与不同的实现。

4.in_pcblookup函数

in_pcblookup函数有几个作用:

1.当TCP或UDP收到一个IP数据报时,in_pcblookup扫描协议的Internet PCB表,寻找一个匹配的PCB,来接收该数据报。

这是运输层对收到的数据报的分用。

2.当进程运行bind系统调用。为某个插口分配一个本地IP地址和本地port号。协议调用in_pcbbind,验证请求的本地地址

对没有被使用。

3.当进程运行bind系统调用,请求给它的插口分配一个暂时port时,内核选了一个暂时port,并调用in_pcbbind检查该端

口是否正在被使用。假设正在被使用。就试下一个port。以此类推。直到找到一个没有被使用的port号。

4.当进程显式或隐式地运行connect系统调用时。in_pcbbind验证请求的插口对是唯一的。

在第2,3,4种情况下,in_pcbbind调用in_pcblookup。

5.in_pcbbind函数

in_pcbbind把一个本地地址和port号绑定到一个插口上。从五个函数中调用它:

1.bind为某个TCP插口调用(通常绑定到server的一个知名port上)

2.bind为某个UDP插口调用(绑定到server的一个知名port上,或者绑定到客户插口的一个暂时port上)

3.connect为某个TCP插口调用。假设该插口还没有绑定到一个非零port上(对TCP客户来说,这是一种典型情况)

4.listen为某个TCP插口调用,假设该插口还没有绑定到一个非零port(这非常少见,由于是TCPserver调用listen。TCPserver

通常绑定到一个知名port上。而不是暂时port)

5.从in_pcbconnect调用。假设本地IP地址和本地port号被置位。

当中1,2为显示绑定。3,4,5为隐式绑定。

6.in_pcbconnect函数

函数in_pcbconnect为插口指定IP地址和外部port号。

有四个函数调用它:

1.connect为某个TCP插口(某个TCP客户的请求)调用。

2.connect为某个UDP插口(对UDP客户是可选的,UDPserver非常少见)调用。

3.当在一个没有连接上的UDP插口上输出数据报时从sendto调用。

4.当一个连接请求(一个SYN报文段)到达一个处于LISTEN状态(对TCPserver是标准的)的TCP插口时。tcp_input调用。

7.in_pcbdisconnect函数

in_pcbdisconnect把UDP插口断连。把外部IP地址设成全0,外部port设成0,就把外部相关内容删除了。

这是在已经在一个未连接的UDP插口上发送一个数据报后。在一个连接上的UDP插口上调用connect时做的。

在第一种情况

下,调用sendto的次序是:UDP调用in_pcbconnect把插口暂时连接到目的地。udp_output发送数据报。然后in_pcbdisconnect

删除暂时连接。

当关闭插口时。不调用in_pcbdisconnect,由于in_pcbdetach处理释放PCB。

仅仅有当一个不同的地址或port号要求重用该PCB

时,才断连。

8.in_pcbnotify、in_rtchange和in_losing函数

当收到一个ICMP差错时。调用in_pcbnotify函数。把差错通知给合适的进程。把差错通知给合适的进程。

通过对全部的PCB

搜索一个协议(TCP或UDP),并把本地和外部IP地址及port号与ICMP差错返回的值进行比較。找到合适的进程。

比如,当

由于一些路由器丢掉了某个TCP报文段而收到ICMP源抑制差错时,TCP必须找到产生该差错的连接的PCB,放慢在该连接

上的传输速度。

下图显示了处理ICMP差错时调用的函数。

当收到一个ICMP报文时。调用icmp_input。icmp的五种报文依照差错来划分:

目的主机不可达

參数问题

重定向

源抑制

超时

每一个协议都定义了它的控制输入函数,即protosw机构中pr_ctlinput。对TCP和UDP,他们各自是tcp_ctlinput和udp_cltinput。

由于收到的ICMP差错中包括了引起差错的数据报的IP首部。全部引起该差错的协议是已知的。这五个ICMP差错中的四个将引起

对协议的控制输入函数的调用。

《TCP/IP具体解释卷2:实现》笔记--协议控制块的更多相关文章

  1. 《TCP/IP具体解释卷2:实现》笔记--IP多播

    D类IP地址(224.0.0.0到239.255.255.255)不识别互联网内的单个接口,但识别接口组,被称为多播组. 单个网络上的组成员利用IGMP协议在系统之间通信. 多播路由器用多播选录协议. ...

  2. 《TCP/IP具体解释卷2:实现》笔记--接口层

    接口层包含在本地网上发送和接收分组的硬件与软件. 我们用设备驱动程序来表示与硬件及网络接口通信的软件,网络接口是指在一个特定网络上硬件与设备驱动器之间的接口. Net/3接口层试图在网络协议和连接到一 ...

  3. 《TCP/IP具体解释卷2:实现》笔记--选路请求和选路消息

    内核的各种协议并不直接使用前面提供的函数来訪问选路树,而是调用几个函数:rtalloc和rtallocl是完毕路由表查询的两个 函数:rtrequest函数用于加入和删除路由表项:另外大多数接口在接口 ...

  4. 《TCP/IP具体解释卷2:实现》笔记--UDP:用户数据报协议

    用户数据报协议.即UDP,是一个面向数据报的简单运输层协议:进程的每次输出操作仅仅产生一个UDP数据报,从而发送 一个IP数据报. 进程通过创建一个Internet域内的SOCK_DGRAM类型的插口 ...

  5. 《TCP/IP具体解释卷2:实现》笔记--ICMP:Internet控制报文协议

    ICMP在IP系统间传递差错和管理报文,是不论什么IP实现必须和要求的组成部分.能够把ICMP分成两类:差错和查询.查询报文 是用一对请求和回答定义的.差错报文通常包括了引起错误的IP包的第一个分片的 ...

  6. 《TCP/IP具体解释卷2:实现》笔记--IP:网际协议

    本章介绍IP分组的结构和主要的IP处理过程,包含输入,转发和输出. 下图显示了IP层常见的组织形式. 在之前的文章中.我们看到了网络接口怎样把到达的IP分组放到IP输入队列ipintrq中去,并怎样调 ...

  7. 《TCP/IP具体解释卷2:实现》笔记--IP的分片和重装

    IP首部内有三个字段实现分片和重装:标识字段(ip_id).标志字段(ip_off的3个高位比特)和偏移字段(ip_off的13个低位 比特).标志字段由3个1bit标志组成.比特0是保留的必须为0, ...

  8. 《TCP/IP具体解释卷2:实现》笔记--域和协议

    Net/3组把协议关联到一个域,而且用一个协议族常量来标识每一个域.Net/3还通过全部的编址方法将协议分组. 在一个域中 的每一个协议使用同类地址.而且每种地址仅仅被一个域使用.作为结果,一个域能通 ...

  9. 《TCP/IP具体解释卷2:实现》笔记--4种不同类型的mbuf

    mbuf的主要用途是保存子进程和网络接口间互相传递的用户数据.但mbuf也用于保存其它各种数据:源于目的地址.插口 选项等等. 以下介绍我们要遇到的四种类型的mbuf,它们根据在成员m_flag中填写 ...

随机推荐

  1. 51nod 矩阵取数问题

    一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. f[i][j] = max(f[i-1][j], f[i][j-1]) + ...

  2. PHP CURL HTTPS POST

    PHP CURL HTTPS POST function vpost($url,$data){ // 模拟提交数据函数    $curl = curl_init(); // 启动一个CURL会话    ...

  3. PyCharm激活方法

    1.激活码激活 1.修改hosts文件 将0.0.0.0 account.jetbrains.com添加到hosts文件最后,windows系统hosts文件路径为:C:\windows\system ...

  4. 【Uva 1627】Team them up!

    [Link]: [Description] 给你n个人; 有一些人之间有认识关系 a认识b,b不一定认识a 让你把这n个人分成两组 使得这两组中的每一组: 组内的人与人之间都相互认识. 并且,使得两组 ...

  5. cogs 26. 分组

    26. 分组 ★   输入文件:dataa.in   输出文件:dataa.out   简单对比时间限制:1 s   内存限制:128 MB[问题描述] 现有 n 个学生, 要分成X1 ,X2 ,.. ...

  6. 欢天喜地迎国庆,国产开源编程语言 RPP 1.87 公布!

    更新例如以下: 1.支持超级宏 2.修复bug 下载地址: https://github.com/roundsheep/rpp 超级宏能够随意定义语法,制约你的仅仅有想象力: void main() ...

  7. Log4j2 与 SpringMVC 整合

    log4j2不仅仅是log4j的简单升级,而是整个项目的重构.官网地址:http://logging.apache.org/log4j/2.x/,大家能够从官网的介绍看出它相比log4j第1代的种种长 ...

  8. solr 亿万级数据查询性能測试

    废话不多说,我电脑配置 i7四核cpu 8G内存 插入数据文档中有5个字段,当中有两个分词.一个int,一个date 批量插入測试一次10万循环10次总共100万用时85秒 批量插入測试一次10万循环 ...

  9. HDU 6182 A Math

    A Math Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. C/C++(结构体)

    结构体(struct) 从某种意义上说,会不会使用struct,如何使用struct是区别一个开发人员是否具备丰富开发经验的试金石. 处理由不同类型成员构成的构造类型,要采用结构体的方式. 定义:关键 ...