用户数据报协议。即UDP,是一个面向数据报的简单运输层协议:进程的每次输出操作仅仅产生一个UDP数据报,从而发送

一个IP数据报。

进程通过创建一个Internet域内的SOCK_DGRAM类型的插口,来訪问UDP。

该类型插口默认地称为无连接的。每次进程发送

数据时,必须指定目的IP地址和port号。

每次从插口上接收数据报时。进程能够从数据报中收到源IP地址和port号。

UDP插口也能够被连接到一个特殊的IP地址和port,这样,全部写到该插口的数据报都被发往该目的地,并且仅仅有来自该IP

地址和port号的数据才被传给该进程。

1.UDP的protosw结构

下图显示了UDP的协议交换入口

2.UDP的首部

UDP首部定义成一个udphdr结构,下图是UDP首部的数据结构和图。

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

在代码中,通常把udp首部作为一个紧跟着UDP首部的IP首部来引用。这就是udp_input怎样处理收到的ip数据报,以及

udp_output怎样构造外出的ip数据报,这样的联合的ip/udp首部是一个udpiphdr结构,例如以下图所看到的:

20个字节的ip首部定义成一个ipovly结构。例如以下图所看到的。不幸的是,这个结构并非一个真正的ip首部。大小尽管同样,可是

字段不同。

3.udp_init函数

domaininit函数在系统初始化时调用udp的初始化函数(udp_init),这个函数所做的唯一的工作是把头部PCB的向前和向

后指针指向它自己。这是一个双向链表。

udb PCB的其它部分都被初始化为0,虽然在这个头部PCB中唯一使用的字段是inp_lport。它是要分配的下一个UDP暂时

port号。

4.udp_output函数

当应用程序调用一下五个写函数中的随意一个时,发生UDP输出。这五个函数是:send,sendto或sendmsg、write或

writev。

假设插口已经连接上,则可随意调用调用这五个函数,虽然用sendto或sendmsg不能指定目的地址。假设插口

还没有连接上,则仅仅能调用sendto和sendmsg。而且必须指定一个目的地址。下图总结了这五个函数。它们在终止时,

都调用udp_output,该函数再调用ip_output。

五个函数终止调用sosend,并把一个指向msghdr结构的指针作为參数传给该函数。要输出的数据被分装在一个mbuf链

上。sosend把一个可选的目标地址和可选的控制信息放在mbuf中。并公布PRU_SEND请求。

udp_output函数的处理流程例如以下:

1.丢掉可选控制信息。udp输出不适用不论什么控制信息。

2.暂时连接一个未连接上的接口。假设调用方为UDP数据报指定了目的地址。则插口是由in_pcbconnect暂时连接到该地址

的。并在该函数的最后被断连。

3.在前面加上ip/udp首部。M_PREPEND在数据的前面为IP和UDP首部分配空间。

4.1.UDP检验和计算和伪首部

在讨论udp_output的后一部分之前,我们描写叙述一下udp怎样填充ip/udp首部的某些字段。怎样计算udp检验和,怎样传递

ip/udp首部及数据给ip输出的,这些工作非常巧妙地使用了ipovly结构。

下图显示了udp_output在由m指向的mbuf链的第一个存储器上构造的28字节ip/udp首部。

没有阴影的字段是udp_output

填充的,有阴影的字段是由ip_output填充的。

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

在计算UDP检验和使用下面三个事实:1.在伪首部中(例如以下图)的第三个32bit字看起来与ip首部中的第三个32bit字类似:

2个8bit值和一个16bit值。2.伪首部中的三个32bit值的顺序是无关的。

其实。internet检验和的计算不依赖于所使用的

16bit值的顺序。

3.在检验和计算中另外再加上一个全0的32bit字没有不论什么影响。

udp_output利用这三个事实。填充udpiphdr结构的字段,例如以下图所看到的。

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

在20字节的ip首部中。最后三个32bit字被用作检验和计算的为首部,ip首部的前两个32bit字也用作检验和计算中。但他们

被初始化为0,不影响最后的检验和。

下图总结了我们描写叙述的操作:

1.上图中最上面的图是为首部的协议定义。

2.中间的图是源码中使用的udpiphdr结构,被用于计算udp检验和。

3.以下的图是出如今线路上的ip/udp首部。上面有箭头的7个字段是udp_output在检验和之前填充的,上面有星号的3个字段

是udp_output在检验和计算之后填充的,其它6个有阴影的字段是ip_output填充的。

以下是udp_output函数的后半部分。

1.为检验和计算准备伪首部。

2.计算检验和

3.填充UDP长度、TTL和TOS。

4.发送数据报。调用ip_output发送数据报。

5.断连暂时连接的插口。

5.udp_input函数

当ip在它的协议字段指定为UDP的输入队列上收到一个IP数据报时,才发生UDP的输入。

IP通过协议交换表中的pr_input

函数调用udp_input。

由于ip的输入是在软件中断级,所以udp_input也在这一级上运行。udp_input的目标是把udp数据报

放置在合适的插口缓存内,唤醒该插口上因输入堵塞的全部进程。
对udp_input函数的讨论分为三个部分:
1.udp对收到的数据报完毕一般性的确认。
2.处理目的地是单播地址的udp数据报:找到合适的pcb,把数据报放到插口的缓存内。

3.处理目的地是广播或多播地址的udp数据报:必须把数据报提交给多个插口。

5.1.对收到的udp数据报的一般确认

1.丢弃IP选项。

2.验证UDP长度。

与UDP数据报相关的两个长度是:IP首部的长度字段(ip_len)和UDP首部的长度字段(uh_ulen)。

比較这两个长度,可能有三种可能性:

1)ip_len等于uh_ulen。这是通常情况。

2)ip_len大于uh_ulen。

ip首部太大。例如以下图所看到的。代码相信两个长度中小的那个,并从数据报的最后移走多余的数据字节,

从mbuf链的最后截断数据。

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

3)ip_len小于uh_ulen。

当udp首部的长度给定时,ip数据报比可能的小。例如以下图所看到的。

这说明数据报有错误,必须丢弃。

没有其它的选择。

3.保存ip首部的备份,验证udp的检验和。

5.2.分用单播数据报

假定数据报的目的地址是一个单播地址。

1.检查“向后一个”快速缓存。udp维护一个指针。该指针指向最后在其上接收数据报的internet pcb。在查看pcb之前,可能必须

搜索udp表上的pcb,把近期一次接收pcb的外部和本地地址以及port号和收到的数据报进行比較。这称为“向后一个”快速缓存。

它是依据这样一个如果。即收到的数据报极有可能要发往上一个数据报发往的同一port。

2.搜索全部的UDP的PCB。

3.生成ICMPport不可达差错。假设没有找到匹配的PCB,UDP通常产生一个ICMPport不可达差错。

4.返回源站IP地址和源站port。

5.处理IP_RECVDSTADDR插口选项。

该选项把收到的UDP数据报中的目的IP地址作为控制信息返回。

6.把数据加到插口的接收队列中。

5.3.分用多播和广播数据报

这些数据报被提交给匹配的全部插口。而不不过一个插口。

6.udp_saveopt函数

假设进程指定了IP_RECVDSTADDR插口选项,则udp_input调用udp_saveopt,从收到的数据报中接收目的IP地址。

7.udp_ctlinput函数

当icmp_input收到一个ICMP差错(目的主机不可达、參数问题、重定向、源站抑制和超时)时,调用对应协议的pr_ctlinput

函数。对于UDP,调用udp_cltinput。我们来看下对收到的ICMP所做的处理:

1.icmp_input把icmp类型和码转换成PRC_xxxx差错码。

2.把PRC_xxxx差错码传给协议的控制输入函数。

3.internet pcb协议(TCP和UDP)把PRC_xxx差错码映射到一个unix的errno值,这个值被返回给进程。

8.udp_usrreq函数

很多操作都要调用协议的用户请求函数,在某个UDP插口上调用五个写函数中的随意一个。都以请求PRU_SEND调用UDP

的用户请求函数结束。以下讨论该函数中各个请求。

1.PRU_ATTACH请求,来自socket系统调用,分配一个新的pcb,把它加到udp pcb表的前面,把插口结构和pcb连接在一起。

2.close系统调用公布PRU_DETACH请求。从udp表中移走pcb。并释放该pcb。

3.PRU_BIND请求完毕绑定操作。

4.假设有PRU_LISTEN请求,则是无效的。仅仅有面向连接的协议才使用它。

5.在一个udp应用程序中。客户或server,能够调用connect,它发送CONNECT请求改动插口发送或接收的外部ip地址和port号。

6.socketpair系统调用公布PRU_CONNECT2请求。

8.对于UDP插口,有两种情况会产生PRU_DISCONNECT请求:

a.当关闭了一个连接上的UDP插口时。在PRU_DETACH之前调用PRU_DISCONNECT。

10.调用无法写函数,公布PRU_SEND请求。终于调用udp_output发送该数据报。

12.PRU_SOCKADDR和PRU_PEERADDR请求分配来自系统调用getsockname和getpeername。

9.udp_sysctl函数

udp的sysctl函数仅仅支持一个选项,udp检验和标志位。

系统管理员能够禁止用sysctl程序使能或精巧udp检验和。

《TCP/IP具体解释卷2:实现》笔记--UDP:用户数据报协议的更多相关文章

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

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

  2. 《TCP/IP具体解释卷2:实现》笔记--协议控制块

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

  3. 【TCP/IP详解 卷一:协议】第十一章 UDP 用户数据报协议

    11.1 引言 UDP 是一个简单的 面向数据报 的运输层协议:进程的每个 输出操作 都正好产生一个 UDP数据报,并且组装成一份待发送的IP数据报. 这与 TCP 不一样,它是 面向流字符 的协议, ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. java面试题之如何判断一个对象是否应该被回收

    常用的有两种办法: 引用计数法:(无法解决对象循环引用的问题,导致对象无法被回收) 可达性分析:

  2. 单线程实现并发——协程,gevent模块

    一 并发的本质 1 切换 2 保存状态 二 协程的概念 协程,又称微线程,纤程.英文名Coroutine.单线程下实现并发,用户从应用程序级别控制单线程下任务的切换,注意一定是遇到I/O才切. 协程的 ...

  3. idea部署项目到远程tomcat

    之前做项目,一直都是把本地的源码上传到svn,服务器是通过ant或者maven脚本来编译的生成项目的.每次都要单独登录接服务器进行项目的部署和发布,感觉特别繁琐.(特别是在有几套服务器的情况下,简直就 ...

  4. Android组件实例化问题

    对于Application. Activity. Notification. BroadCast. Service 这些组件的使用,对象的实例化问题各有不同,如何实例化以及在什么时候实例化也所有不同. ...

  5. 32深入理解C指针之---字符串操作

    一.字符串操作主要包括字符串复制.字符串比较和字符串拼接 1.定义:字符串复制strcpy,字符串比较strcmp.字符串拼接strcat 2.特征: 1).必须包含头文件string.h 2).具体 ...

  6. Beyond compare vs kdiff3

    這裡使用的 kdiff3 版本是 0.9.98   基於以下 三點,最終選擇了 beyond compare   1. kdiff3 不能刪檔案,     以下為例,不能刪1   2. kdiff3 ...

  7. ubuntu16.04下安装wine1.8.2

    如果是amd64则需要执行这个: sudo dpkg --add-architecture i386 1 1 添加wine最新的源 sudo add-apt-repository ppa:wine/w ...

  8. 输入框为数字类型时防止maxlength属性不起作用

    <input type="number" oninput="if(value.length>5)value=value.slice(0,5)" /& ...

  9. Windows Phone 8 与 windows 8 开发技术概览

    目前来说Windows phone 8的开发者 大家都是走战斗在在技术朋友,相信大家在做Windows Phone 8开发的同时也在关注Windows 8,我相信很多开发者一定是在 Windows 8 ...

  10. HBase 基本操作

    如何添加列族 很简单,跟rdbms一样 直接用alter,但是alter之前必须先disable这个表 ---->disable 'test'                          ...