UNP总结 Chapter 26~29 线程、IP选项、原始套接字、数据链路访问

来源:互联网 发布:万网域名备案要多久 编辑:程序博客网 时间:2024/05/01 12:15


 此为UNP最后一段总结 Chapter30主要为代码实践 请参考UNP

 

一、线程

这里UNP的线程与APUE中讲得线程基本一致,但是APUE讲得更加细致,所以这里只列出主要内容(线程数据会稍微详细) 详细见APUE线程相关章节 或者本博文中的APUE专题

1.基本线程函数:创建与终止

2.线程特定数据

使用线程特定数据是使现成函数线程安全的常用技巧

这里重点提一下的是

1).每个系统支持有限数量的线程特定数据项。系统(很可能是线程库)为每个进程维护一个数据结构,我们称之为Key结构,如下图

2).Key结构中的标志指示这个数组元素是否正在使用,所有的标志初始化为"不在使用"。当一个线程调用pthread_key_create创建一个新线程特定数据项时,系统搜索其Key结构数组并找到第一个未被使用的项。其下标(0~127)称做键(key),这个下标返回给调用线程。我们很快谈到Key结构的另一个成员“析构函数指针”。

除了进程范围内的Key结构数组外,系统还为进程的每个线程维护多条信息。这些特定于线程的信息我们称之为Pthread结构,其部分内容是我们称之为pkey数组的一个128个元素的指针数组,如下图:

3).下图给出示意图:把malloc到的内存区和线程特定数据指针相关联

4).线程n初始化它的线程特定数据后的数据结构

3.互斥锁

4.条件变量

 

 

二、IP选项

1.概述

IPv4允许在20字节首部固定部分之后跟以最多40字节的选项。尽管已经定义的IPv4选项公有10种,最常用的是源路径选项,这些选项的访问途径是存取IP_OPTIONS套接字选项。

IPv6允许在固定长度40字节IPv6头部和传输层头部(如ICMPv6,TCP或UDP)之间出现扩展头部(extension header)。和IPv4不同的是,访问IPv6扩展头部的途径是通过函数接口进行,而不是强迫用户去理解头部如何出现在IPv6分组中的真实细节。

 

2.IPv4选项、IPv4源路径选项

1).读取和设置IP选项字段使用getsockopt和setsockopt(level参数为IPPROTO_IP,optname参数为IP_OPTIONS)。getsockopt和setsockopt的第四个参数是指向一个缓冲区(大于小于等于44字节)的指针,第五个参数是该缓冲区的大小。

2).使用setsockopt设置了IP选项之后,在相应套接字发送的所有IP数据报都将包括这些选项。套接字可以是TCP,UDP或原始IP套接口。为了清除这些选项,可以调用setsockopt,置第四个参数为空指针,或者置第五个参数(长度)为0

3).当调用getsockopt获取一个由accept创建的已连接TCP套接字的IP选项时,返回的是在相应监听套接字上收到的客户的SYN中源路径选项的逆转。源路径自动被TCP倒序,因为由客户指定的是从客户到服务器的源路径,服务器需要在发送到客户的数据中使用该路径的逆转

4).源路径是由IP数据报的发送者指定的一个IP地址列表。如果源路径是严格的(strict),那么数据报必须且只能逐一经过所列的节点。如果源路径是宽松的(loose),数据报必须逐一经过所列的节点,不过也可以经过未在源路径中列出的节点。

 

下图展现向内核的源路径

下图展现getsockopt返回的源路径选项格式

详细代码示例参见UNP

 

3.IPv扩展首部

  • 步跳(hop_by_hop)选项必须紧跟40字节的IPv6头部。目前没有定义这种可供应用程序使用的选项。
  • 目的(destination)选项:目前没有定义这种可供应用程序使用的选项。
  • 路由头部(routing header):这是一个源路由选项,在概念上类似于我们在24.3节中描述的IPv4源路径选项。
  • 分片头部(fragmentation hearder):该头部由将IPv6数据报分片的主机自动生成,有最终的目的主机重组片段时处理。
  • 认证头部(authentication header, AH):
  • 封装安全有效负载(encapsulating security payload, ESP)头部:

4.IPv6路由首部

下图展现IPv6路由首部:

 

5.IPv6粘附选项

  • IPv6分组信息
  • 外出跳限干或跳限
  • 下一条地址
  • 外出流通类别或者接受流通类别
  • 步跳选项
  • 目的地选项
  • 路由首部

 

 

三、原始套接字

1.概述

原始套接口提供以下三种TCP及UDP套接口一般不提供的功能。

1). 有了原始套接字,进程可以读写ICMPv4,IGMPv4,ICMPv6分组。例如:Ping程序,就使用原始套接字发送ICMP回射请求,并接受ICMP回射应答。

2). 有了原始套接字,进程可以读写内核不处理其协议字段的IPv4数据报。

3). 有了原始套接字,进程还可以利用IP_HDRINCL套接字选项可以构造自己的IPv4首部。

 

2.原始套接字创建

创建一个原始套接字涉及以下几步:

1). 当第二个参数是SOCK_RAW时,调用socket函数,以创建一个原始套接字。第三个参数(协议)一般不应为0,例如,为了创建一个IPv4原始套接口,我们可以这样写:

int sockfd;sockfd = socket(AF_INET, SOCK_RAW, protocol);

其中protocol参数值为形如IPPROTO_xxx的常值,由<netinet/in.h>头文件定义,如IPPROTO_IGMP

 

2).可以设置IP_HDRINCL套接字选项:

const int on = 1;if ( setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0 )       出错处理

 

3).可以在这个原始套接字上调用bind函数,不过不过比较少见。bind函数仅用来设置本地地址:因为原始套接字不存在端口号的概念。就输出而言,调用bind设置的是将用于从这个原始套接字发送的所有数据的源IP地址(只在IP_HDRINCL套接字选项未开启的前提下),若果不调用bind,内核就把IP地址设置为外出接口的主IP地址。

 

4).可以在这个原始套接字上可调用connect函数,不过也比较少见。connect函数仅仅设置外地地址,同样因为因为原始套接字不存在端口号的概念。对于输出而言,调用connect之后,我们可以把sendto调用改为write或send调用,因为目的IP地址已经指定了。

 

3.原始套接字输出

原始套接字的输出遵循以下规则:

1). 普通输出通过调用sendto或sendmsg并指定目的IP地址来完成。如果套接字已经连接,那么也可以调用write,writev或send

2). 如果IP_HDRINCL选项未开启,那么由进程让内核发送的数据的起始地址指的IP首部之后的第一个字节。因为内核将构造IP首部并把它置于来自进程的数据之前,内核把IPv4首部的协议字段设置成来自socket调用的第三个参数。

3). 如果IP_HDRINCL铜戒指选项已开启,那么由进程让内核写的数据起始地址指IP首部的第一个字节。

4). 内核会对超出外出接口MTU的原始分组执行分片。

 

4.原始套接字输入

内核把收到的IP数据报传递到原始套接字要遵循规则:

  • 接收到的TCP分组和UDP分组决不会传递给任何原始套接字
  • 大多数ICMP分组在内核处理完其中的ICMP消息后传递到给原始套接字
  • 所有IGMP分组在内核完成处理其中的IGMP消息之后传递到原始套接口字
  • 内核不认识其协议字段的IP数据报传递到原始套接字
  • 如果某个数据报以片段形式到达,则该分组将在所有片段到达并重组后才传给原始套接字。

 

5.ping程序

ping程序的操作非常简单,往某个IP地址发送一个ICMP回射请求,该节点则以一个ICMP回射应答,概貌如下 程序详见UNP

 

 

6.traceroute程序

traceroute的用途是确定从我们的主机到目的地之间IP数据报行进的路径,traceroute使用IPv4的TTL字段或IPv6的跳限字段以及两个ICMP消息。它一开始向目的主机发送一个TTL(或跳限)为1的UDP数据报。这个数据报导致头一跳的路由器返回一个“time exceeded in transmit(传输中超时)”错。接着每次对TTL加1,并分别发出UDP数据报,这样可以逐步确定下一个路由器。当UDP数据报终于到达目的主机时,希望目的主机能返回一个“port unreachable(端口不可达)”错,这通过向一个期望未被使用的随机端口发送UDP数据报来实现

 

7.一个ICMP消息守护程序

这里给出描述图 代码见UNP

 

从icmpd获取绑定在那个UDP套接字上的端口号之后就关闭该套接字的本地副本后,icmpd一旦收取由该应用进程通过绑定在它的UDP套接字上的端口发送的UDP数据报所引发的ICMP错误,就通过Unix域连接向该应用程序发送一条信息。

 

 

 

 

 

四、数据链路访问

这里仅列出主要内容

1.BPF:BSD分组过滤器

2.DLPI:数据链路提供接口

3.Linux:SOCK_PACKET和PF_PACKET

4.libpcap:分组捕获函数库

5.libnet:分组构造与输出函数库

6.检查UDP的校验与字段

 

原创粉丝点击