请教Linux网络netty 接收16进制报文方向的非线性报文

1、应用层协议有:ping,telnet,OSPF,DNS;传输层协议:TCP(对应应用层的telnet和网络层的ip协议)和UDP(对应应用层的DNS和IP协议),网络层协议:ICMP(对应应用层的ping协议和网络层的IP协议)和IP协议。数据链路层协议:ARP,Data Link,RARP协议(本层协议对应网络层的IP协议)。
2、数据链路层两个常用的协议是ARP协议(地址解析协议)和RARP(逆地址解析协议)。
3、网络层实现数据包的选路和转发。网络层的任务就是选择这些中间节点,以确定两台主机之间的通讯路劲。网络层对上层协议隐藏了网络拓扑连接的细节。ICMP协议是因特网控制报文协议,它是IP协议的重要补充,主要用来检测网络连接。
4、ICMP报文分为两大类:一类是差错报文,这类报文主要用来回应网络错误,比如目标不可到达和重定向;另一类是查询报文,这类报文用来查询网络信息,比如ping程序就是使用ICMP报文查看目标是否可到达。其中重定向报文使用代码值0表示对网络重定向,代码值1表示对主机重定向。ICMP报文报文使用16位校验码和字段对整个报文进行循环冗余校验,以检验报文在传输过程中是否损坏。
5、传输层为两台主机上的应用层程序提供端到端的通讯,传输层只关心通信的起始端和目的端,而不在乎数据包的中转过程。传输层为应用程序封装了一条端到端的逻辑通信链路,它负责数据的收发,链路的超时重连等。
6、数据链路层、网络层和传输层负责处理网络通讯细节,这部分必须既稳定又高效,他们都是在内核空间中实现。应用层则在用户空间实现,它主要负责处理众多逻辑,不服文件传输、名称查询和网络管理等。
7、UDP和TCP封装过程类似,不同的是UDP无需为应用层数据保存副本,因为他提供的服务是不可靠的。
8、TCP报文段和UDP数据报通过其头部的16位的端口号字段来区分上层协议程序。DNS协议对应的端口是53,HTTP协议对应的端口号是80,。
9、以太网ARP请求/应答报文的格式如下:硬件类型2个字节,协议类型2个字节,硬件地址长度1个字节,协议地址长度1个字节,操作2个字节,发送端以太网地址6个字节,发送端IP地址4个字节,目标端以太网地址6个字节,目标端IP地址4个字节。
10、socket定义一组API提供的如下功能:一是将应用程序数据从用户缓冲区中复制到TCP/UDP内核发送缓冲区,以交付内核来发送数据,或者是从内核TCP/UDP接收缓冲区中复制数据到用户缓冲区,以读取数据;二是应用程序可以通过他们来修改内核中各层协议的某些头部信息或其他数据结构,从而精细地控制底层通信的行为。
11、IP头部信息出现在每个IP数据报中,用于指定IP通讯的源端IP地址、目的端IP地址,指导IP分片和重组,以及指定部分通讯行为。
IP数据报的路由和转发发生在除目标机器之外的所有主机和路由器上。它们决定数据报是否应该转发以及如何转发。
12、IPv4头部结构:4位版本号,4位头部长度,8位服务类型(TOS)16位总长度(字节数)是指整个IP数据报的长度&& 16位标识唯一地标识主机发送的每一个数据报& 3位标识字段的第一位保留& 13位分片偏移是分片相对原始IP数据报开始出的偏移& 8位生存时间& 8位协议用来区分上层协议& 16位头部校验和由发送端填充,接收端对其使用CRC算法以检验IP数据报头部在传输过程中是否损坏&& 32位的源端IP地址和目的端IP地址用来标识数据包的发送端和接收端&&&IPv4最后一个选项字段是可变长的可选信息,可选信息包括记录路由、时间戳、松散源路由选择&&
严格源路由选择。
13、测试机器上执行telnet命令登录本机:sudo tcpdump -ntx -telnet 127.0.0.1。
14、ICMP重定向报文:ICMP重定向报文的类型值是5(8位类型);代码字段有4个可选址(8位代码),默认写为1;16位校验和;应该使用的路由器的IP地址;原始IP数据报的头部信息(包括可选字段)+数据部分的前8字节。
15、TCP协议:TCP头部信息、TCP状态转移过程:TCP连接到断开的整个过程中的状态迁移、TCP数据流:交互数据流和成块数据流、TCP数据流的控制:超时重传和拥塞控制。
16、当接受端收到一个或多个TCP报文段后,TCP模块将它们携带的应用程序数据按照TCP报文段依次放入TCP接收缓存中,病通知应用程序读取数据。接收端应用程序可以一次性将TCP接收缓冲区中的数据全部读出,也可以分多次读取,这取决于用户指定的应用程序读缓冲区的大小。因此,应用程序执行的读操作次数和TCP模块接收到的TCP报文段个数之间也没有固定的数量关系。UDP模块就将其封装成一个UDP数据报并发送值。接收端必须及时针对每一个UDP数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取UDP数据,则UDP数据将被截断。
17、TCP固定头部结构:16位端口号;32位序号:一次TCP通讯过程中某一个传输方向上的字节流的每个字节的编号;32位确认号;4位头部长度;6位标志位:URG标志,ACK标志,PSH标志,RST标志,SYN标志,FIN标志;16位窗口大小;16位校验和;16位紧急指针。
18、TCP半关闭状态,连接超时(重新连接多次然后超过重连时间)等情况的了解。connect连接失败有连个原因,目标端口不存在,或是在超时时间内未收到服务器确认报文段。
19、复位报文段:TCP连接的一端会向另一端发送携带RST标志的报文段,即复位报文段,以通知对方关闭连接或重新建立连接。
产生复位报文段的3种情况:(1)访问不曾在的端口,(2)异常终止连接,(3)处理半打开连接
21、大端字节序是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。小端字节序则是指整数的高字节存储在内存的高地址处,而低位字节则存储在内存的低地址处。linux提供了4个函数来完成主机字节序和网络字节序之间的转换,函数名是:htol,htons,ntohl,ntohs。
22、IPv4地址和用网络字节序整数表示的地址之间的转换的函数名为:inet_addr,inet_aton,inet_ntoa,inet_pton,inet_ntop。
23、linux系统提供一个守护进程来处理系统日志——syslogd,升级版为——rsyslogd。rsyslogd守护进程既能够接收用户进程输出的日志,又能够接收内核日志。用户进程是通过调用syslog函数生成系统日志的。该函数将日志输出到一个UNIX本地域socket类型的文件/dev/log中,rsyslogd则监听该文件以获取用户进程的输出。内核日志由printk等函数打印至内核的环状缓存中。环状缓存的内容直接映射到/proc/kmsg文件中。rsyslogd则通过读取该日志获得内核日志。默认情况下,调试信息会保存至/var/log/debug文件,普通信息保存至/var/log/messages文件,内核消息保存至/var/log/kern.log文件。rsyslogd的主配置文件是/etc/rsyslog,.conf,包含:内核日志输入路径,是否接受UDP日志及监听端口,是否接受TCP日志及监听端口,日志文件的权限,包含哪些自配置文件。
24、C/S模型:所有客户端都通过访问服务器来获取所需的资源。服务器启动后,首先创建一个或多个监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户端连接。服务端稳定运行之后,客户端就可以调用connect函数向服务器发起连接了。由于客户连接请求是随机到达的异步事件,服务器需要使用某种I/O模型来监听这一事件。服务器使用的是I/O复用技术之一的select系统调用。当监听到连接请求后,服务器就调用accept函数接收它,病分配一个逻辑单元为新的连接服务。服务器给客户端分配的逻辑单元是由fork系统调用创建的子进程。
25、I/O处理单元是服务器管理客户连接的模块。它通常要完成以下工作:等待并接受行的客户连接,接收客户数据,将服务器响应数据返回给客户端。但是,数据的收发不一定在I/O处理单元中执行,也可能在逻辑单元中执行。对于一个服务器机群来说,I/O处理单元是一个专门的接入服务器。他实现负载均衡,从所有逻辑服务器中选取负载最小的一台来为新客户服务。
26、一个逻辑单元通通常是一个进程或线程。他分析并处理客户数据,然后将结果传递给I/O处理单元或者直接发送给客户端。对服务器机群而言,一个逻辑单元本身就是一台逻辑服务器。服务器通常拥有多个逻辑单元,以实现对多个客户任务的并行处理。
27、网络存储单元可以是数据库、缓存和文件,甚至是一台独立的服务器。但它不是必须的,比如ssh、telnet等登录服务就不需要这个单元。
28、请求队列是各单元之间的通信方式的抽象。I/O处理单元接收到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求。同样,过个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理竟态条件。对于服务器机群而言,请求队列是各台服务器之间预先建立的、静态的、永久的TCP连接。这种TCP连接能够提高服务器之间交换数据的效率,因为它避免了动态创建TCP连接导致的额外的系统开销。
29、select系统调用的用途是:在一段指定的时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等时间。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5926次
排名:千里之外
原创:22篇
(1)(2)(1)(1)(1)(7)(4)(1)(1)(4)(7)(1)比特客户端
您的位置:
详解大数据
详解大数据
详解大数据
详解大数据
Linux网络报文接收与发送概述
  这种方式最大的好处是:在dev-&poll函数中,不一定只处理一个报文。具体怎么处理可以由驱动程序灵活控制。比如说,假设现在网络负载非常大,如果网络设备每接收一个报文都通过一次中断来告知内核,这样做效率并不理想。而此时dev-&poll可以做一些轮询的工作,如果网络设备已经接收了多个报文,可以一次性都处理了。并且,就算设备此刻所接收到的报文都已经处理完了,驱动程序也可以根据某种方式预判设备在很短的一段时间内还将收到报文,于是依然将自己对应的dev结构留在poll_中,等待下一次继续被调度。
  当dev仍结构留在poll_list中时,设备驱动程序可以关闭设备接收到报文时的中断通知,因为目前处于轮询状态。而当驱动程序认为在将来的一段时间以内无报文可收时,则可以将其dev从poll_list中移除,然后开启设备接收到报文时的中断通知。等待下一次报文接收的中断到来时,这个dev再重新被放入poll_list。
  netif_receive_skb(skb);
  该函数会将skb提交给抓包程序进行处理、还会触发数据链路层的桥接功能(见《网桥浅析》)、然后将报文提交给网络协议栈的上层(网络层)进行处理。
  网络层的协议有IP、等等很多种,在这里怎么知道这个skb该提交给哪种协议呢?在报文的数据链路层报头中保存着三个重要信息,发送者和接收者的地址、和上层协议标识。回想一下之前的流程,在skb接收完成之后我们就已经设置了skb-&protocol(从报头中得到),上层协议就由它来指定。比如,0x0800代表IP协议、0x0806代表,这是由协议规定的。
  netif_receive_skb并不是用一个switch-case来匹配skb-&protocol,以选择网络层处理函数的。系统中有一个名为ptype_base的hash表,各种网络层的协议在其初始化时都会在这个hash表中注册一个类型为packet_type的表项(以协议类型为key),如下图所示(摘自ULNI):
  netif_receive_skb要做的就是在这个hash表中遍历所有type与skb-&protocol匹配的packet_type结构(packet_type结构的dev可用于限定skb-&dev,NULL表示不限),然后调用其func回调函数。(可见,一个报文有可能被多种协议所处理。)
  至此报文被提交到了网络层,在这里就不继续深入了。
  报文的发送
  报文的发送是由网络协议栈的上层发起的。网络协议栈上层构造一个需要发送的skb结构后(该skb已经包含了数据链路层的报头),调用dev_queue_xmit函数进行发送;
  dev_queue_xmit(skb);
  该函数先会处理一些缓冲区重组、计算校验和之类的杂事,然后开始处理报文的发送。
  发送报文有两种策略,有队列或无队列。这是由网络设备驱动程序在定义其对应的dev结构时指定的,一般的设备都会使用队列。
  dev-&qdisc指向一个队列的实例,里面包含了队列本身以及操作队列的方法(enqueue、dequeue、requeue)。这些方法的集合组成了一种队列规则(skb将以某种规则入队、以某种规则出队,并不一定是简单的先进先出),这样的规则可用于流量控制。
  网络设备驱动程序可以选择自己的设备使用什么样的队列,或是不使用队列。
  对于有队列的设备,dev_queue_xmit调用dev-&qdisc-&enqueue方法将skb加入队列,然后调用qdisc_run函数。而qdisc_run会调用qdisc_restart来对队列进行处理。
  qdisc_restart(dev);
  该函数主要的工作就是不断调用dev-&qdisc-&dequeue方法从队列中取出待发送的报文,然后调用dev-&hard_start_xmit方法进行发送。该方法是由设备驱动程序实现的,会直接和网络设备去打交道,将报文发送出去。
  如果报文发送失败,qdisc_restart会调用dev-&qdisc-&requeue方法将skb重新放回队列。同时,还将调用netif_schedule函数将dev加入softdate_net的output_queue队列中(其中的设备都是有报文等待发送的,将在稍后被处理)。然后触发一次NET_TX_SOFTIRQ软中断。于是在下一个中断到来时,对应的软中断处理函数net_tx_action将被调用。
  而如果dev-&hard_start_xmit方法发送报文成功,则表示报文已经送到了网络设备的发送缓冲区,设备会自动将报文发送出去。并且在报文发送完成时,设备会通过中断通知驱动程序。对应的中断处理函数也会触发NET_TX_SOFTIRQ软中断。此外,已发送完成的skb将被加入softdate_net的completion_queue队列中,等待被释放。
  软中断NET_TX_SOFTIRQ被触发,将使得net_tx_action函数被调用。该函数主要做了两件事:
  1、从softdate_net的completion_queue队列中取出每一个skb,将其释放;
  2、对于softdate_net的output_queue队列中的dev,调用qdisc_run继续尝试发送其qdisc队列中的报文;
  对于有队列的设备,其队列主要用于流量控制以及发送失败时的缓冲;对于没有队列的设备(比如lo,环回设备),dev_queue_xmit函数则会直接调用dev-&hard_start_xmit进行发送,如果失败报文就会被丢弃。
  以上过程如图所示:
  qdisc_restart函数在执行过程中还会关心dev是否被暂停(就如接收报文时要关心网络是否拥塞一样),如果被暂停则结束处理流程并返回。
  而dev的暂停与否是由设备驱动程序来设置的,在dev-&hard_start_xmit函数中,驱动程序如果发现设备当前的发送缓冲区太小(比如小到无法再容纳一个报文。这表示报文发送过快,以致于设备来不及处理),则会让设备暂停。而当网络设备在完成报文的发送后会产生中断,对应的中断处理程序又可以根据设备当前的发送缓冲区大小,决定是否让设备从暂停中恢复。
  而如果网络设备出现问题,无法发送报文了,则可能设备上的发送缓冲区一直处于被占满的状态,导致设备一直被暂停。另一方面,报文发不出去,也就不会有通知发送完成的中断产生,设备也就不会从暂停状态恢复,于是网络就瘫痪了。
  为了检测这种情况,驱动程序可以为设备设置一个看门狗定时器。如果发现设备正在暂停状态,并且距离最后一次发送报文已经过去一定的时间,而发送完成的中断还没有收到,则认为该设备出现问题。此时看门狗定时器将触发驱动程序提供的相关函数,将设备复位,以试图让其恢复正常工作。
[ 责任编辑:刘军 ]
去年,手机江湖里的竞争格局还是…
甲骨文的云战略已经完成第一阶段…
软件信息化周刊
比特软件信息化周刊提供以数据库、操作系统和管理软件为重点的全面软件信息化产业热点、应用方案推荐、实用技巧分享等。以最新的软件资讯,最新的软件技巧,最新的软件与服务业内动态来为IT用户找到软捷径。
商务办公周刊
比特商务周刊是一个及行业资讯、深度分析、企业导购等为一体的综合性周刊。其中,与中国计量科学研究院合力打造的比特实验室可以为商业用户提供最权威的采购指南。是企业用户不可缺少的智选周刊!
比特网络周刊向企业网管员以及网络技术和产品使用者提供关于网络产业动态、技术热点、组网、建网、网络管理、网络运维等最新技术和实用技巧,帮助网管答疑解惑,成为网管好帮手。
服务器周刊
比特服务器周刊作为比特网的重点频道之一,主要关注x86服务器,RISC架构服务器以及高性能计算机行业的产品及发展动态。通过最独到的编辑观点和业界动态分析,让您第一时间了解服务器行业的趋势。
比特存储周刊长期以来,为读者提供企业存储领域高质量的原创内容,及时、全面的资讯、技术、方案以及案例文章,力求成为业界领先的存储媒体。比特存储周刊始终致力于用户的企业信息化建设、存储业务、数据保护与容灾构建以及数据管理部署等方面服务。
比特安全周刊通过专业的信息安全内容建设,为企业级用户打造最具商业价值的信息沟通平台,并为安全厂商提供多层面、多维度的媒体宣传手段。与其他同类网站信息安全内容相比,比特安全周刊运作模式更加独立,对信息安全界的动态新闻更新更快。
新闻中心热点推荐
新闻中心以独特视角精选一周内最具影响力的行业重大事件或圈内精彩故事,为企业级用户打造重点突出,可读性强,商业价值高的信息共享平台;同时为互联网、IT业界及通信厂商提供一条精准快捷,渗透力强,覆盖面广的媒体传播途径。
云计算周刊
比特云计算周刊关注云计算产业热点技术应用与趋势发展,全方位报道云计算领域最新动态。为用户与企业架设起沟通交流平台。包括IaaS、PaaS、SaaS各种不同的服务类型以及相关的安全与管理内容介绍。
CIO俱乐部周刊
比特CIO俱乐部周刊以大量高端CIO沙龙或专题研讨会以及对明星CIO的深入采访为依托,汇聚中国500强CIO的集体智慧。旨为中国杰出的CIO提供一个良好的互融互通 、促进交流的平台,并持续提供丰富的资讯和服务,探讨信息化建设,推动中国信息化发展引领CIO未来职业发展。
IT专家新闻邮件长期以来,以定向、分众、整合的商业模式,为企业IT专业人士以及IT系统采购决策者提供高质量的原创内容,包括IT新闻、评论、专家答疑、技巧和白皮书。此外,IT专家网还为读者提供包括咨询、社区、论坛、线下会议、读者沙龙等多种服务。
X周刊是一份IT人的技术娱乐周刊,给用户实时传递I最新T资讯、IT段子、技术技巧、畅销书籍,同时用户还能参与我们推荐的互动游戏,给广大的IT技术人士忙碌工作之余带来轻松休闲一刻。
微信扫一扫
关注Chinabyte推荐这篇日记的豆列
······主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
傻丫头和高科技产物小心翼翼的初恋
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:。个人QQ群:、
个人大数据技术博客:
人生得意须尽欢,莫使金樽空对月。
1. Linux 网络路径
1.1 发送端1.1.1 应用层(1) Socket应用层的各种网络应用程序基本上都是通过 Linux Socket 编程接口来和内核空间的网络协议栈通信的。Linux Socket 是从 BSD Socket 发展而来的,它是 Linux 操作系统的重要组成部分之一,它是网络应用程序的基础。从层次上来说,它位于应用层,是操作系统为应用程序员提供的 API,通过它,应用程序可以访问传输层协议。
socket 位于传输层协议之上,屏蔽了不同网络协议之间的差异
socket 是网络编程的入口,它提供了大量的系统调用,构成了网络程序的主体
在Linux系统中,socket 属于文件系统的一部分,网络通信可以被看作是对文件的读取,使得我们对网络的控制和对文件的控制一样方便。
UDP socket 处理过程
TCP Socket 处理过程(2) 应用层处理流程
网络应用调用Socket API socket (int family, int type, int protocol) 创建一个 socket,该调用最终会调用 Linux system call socket() ,并最终调用 Linux Kernel 的 sock_create() 方法。该方法返回被创建好了的那个 socket 的 file descriptor。对于每一个 userspace 网络应用创建的 socket,在内核中都有一个对应的 struct socket和 struct sock。其中,struct sock 有三个队列(queue),分别是 rx , tx 和 err,在 sock 结构被初始化的时候,这些缓冲队列也被初始化完成;在收据收发过程中,每个 queue 中保存要发送或者接受的每个 packet 对应的 Linux 网络栈 sk_buffer 数据结构的实例 skb。
对于 TCP socket 来说,应用调用 connect()API ,使得客户端和服务器端通过该 socket 建立一个虚拟连接。在此过程中,TCP 协议栈通过三次握手会建立 TCP 连接。默认地,该 API 会等到 TCP 握手完成连接建立后才返回。在建立连接的过程中的一个重要步骤是,确定双方使用的 Maxium Segemet Size (MSS)。因为 UDP 是面向无连接的协议,因此它是不需要该步骤的。
应用调用 Linux Socket 的 send 或者 write API 来发出一个 message 给接收端
sock_sendmsg 被调用,它使用 socket descriptor 获取 sock struct,创建 message header 和 socket control message
_sock_sendmsg 被调用,根据 socket 的协议类型,调用相应协议的发送函数。
对于 TCP ,调用 tcp_sendmsg 函数。
对于 UDP 来说,userspace 应用可以调用 send()/sendto()/sendmsg() 三个 system call 中的任意一个来发送 UDP message,它们最终都会调用内核中的 udp_sendmsg() 函数。
1.1.2 传输层传输层的最终目的是向它的用户提供高效的、可靠的和成本有效的数据传输服务,主要功能包括
(1)构造 TCP segment
(2)计算 checksum
(3)发送回复(ACK)包
(4)滑动窗口(sliding windown)等保证可靠性的操作TCP 协议栈的大致处理过程如下图所示: TCP 栈简要过程:
tcp_sendmsg 函数会首先检查已经建立的 TCP connection 的状态,然后获取该连接的 MSS,开始 segement 发送流程。
构造 TCP 段的 playload:它在内核空间中创建该 packet 的 sk_buffer 数据结构的实例 skb,从 userspace buffer 中拷贝 packet 的数据到 skb 的 buffer。
构造 TCP header。
计算 TCP 校验和(checksum)和 顺序号 (sequence number)。
TCP 校验和是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。TCP校验和覆盖 TCP 首部和 TCP 数据。
TCP的校验和是必需的
发到 IP 层处理:调用 IP handler 句柄 ip_queue_xmit,将 skb 传入 IP 处理流程。
UDP 栈简要过程:
UDP 将 message 封装成 UDP 数据报
调用 ip_append_data() 方法将 packet 送到 IP 层进行处理。
1.1.3 IP 网络层 - 添加header 和 checksum,路由处理,IP fragmentation网络层的任务就是选择合适的网间路由和交换结点, 确保数据及时传送。网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息- -源站点和目的站点地址的网络地址。其主要任务包括
(1)路由处理,即选择下一跳
(2)添加 IP header
(3)计算 IP header checksum,用于检测 IP 报文头部在传播过程中是否出错
(4)可能的话,进行 IP 分片
(5)处理完毕,获取下一跳的 MAC 地址,设置链路层报文头,然后转入链路层处理。IP 头:IP 栈基本处理过程如下图所示:
首先,ip_queue_xmit(skb)会检查skb-&dst路由信息。如果没有,比如套接字的第一个包,就使用ip_route_output()选择一个路由。
接着,填充IP包的各个字段,比如版本、包头长度、TOS等。
中间的一些分片等,可参阅相关文档。基本思想是,当报文的长度大于mtu,gso的长度不为0就会调用 ip_fragment 进行分片,否则就会调用ip_finish_output2把数据发送出去。ip_fragment 函数中,会检查 IP_DF 标志位,如果待分片IP数据包禁止分片,则调用 icmp_send()向发送方发送一个原因为需要分片而设置了不分片标志的目的不可达ICMP报文,并丢弃报文,即设置IP状态为分片失败,释放skb,返回消息过长错误码。
接下来就用 ip_finish_ouput2 设置链路层报文头了。如果,链路层报头缓存有(即hh不为空),那就拷贝到skb里。如果没,那么就调用neigh_resolve_output,使用 ARP 获取。
1.1.4 数据链路层 功能上,在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路,通过差错控制提供数据帧(Frame)在信道上无差错的传输,并进行各电路上的动作系列。数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。在这一层,数据的单位称为帧(frame)。数据链路层协议的代表包括:SDLC、HDLC、PPP、STP、帧中继等。实现上,Linux 提供了一个 Network device 的抽象层,其实现在 linux/net/core/dev.c。具体的物理网络设备在设备驱动中(driver.c)需要实现其中的虚函数。Network Device 抽象层调用具体网络设备的函数。1.1.5 物理层 - 物理层封装和发送
物理层在收到发送请求之后,通过 DMA 将该主存中的数据拷贝至内部RAM(buffer)之中。在数据拷贝中,同时加入符合以太网协议的相关header,IFG、前导符和CRC。对于以太网网络,物理层发送采用CSMA/CD,即在发送过程中侦听链路冲突。
一旦网卡完成报文发送,将产生中断通知CPU,然后驱动层中的中断处理程序就可以删除保存的 skb 了。
1.1.6 简单总结1.2 接收端1.2.1 物理层和数据链路层简要过程:
一个 package 到达机器的物理网络适配器,当它接收到数据帧时,就会触发一个中断,并将通过 DMA 传送到位于 linux kernel 内存中的 rx_ring。
网卡发出中断,通知 CPU 有个 package 需要它处理。中断处理程序主要进行以下一些操作,包括分配 skb_buff 数据结构,并将接收到的数据帧从网络适配器I/O端口拷贝到skb_buff 缓冲区中;从数据帧中提取出一些信息,并设置 skb_buff 相应的参数,这些参数将被上层的网络协议使用,例如skb-&protocol;
终端处理程序经过简单处理后,发出一个软中断(NET_RX_SOFTIRQ),通知内核接收到新的数据帧。
内核 2.5 中引入一组新的 API 来处理接收的数据帧,即 NAPI。所以,驱动有两种方式通知内核:(1) 通过以前的函数netif_rx;(2)通过NAPI机制。该中断处理程序调用 Network device的 netif_rx_schedule 函数,进入软中断处理流程,再调用 net_rx_action 函数。
该函数关闭中断,获取每个 Network device 的 rx_ring 中的所有 package,最终 pacakage 从 rx_ring 中被删除,进入 netif _receive_skb 处理流程。
netif_receive_skb 是链路层接收数据报的最后一站。它根据注册在全局数组 ptype_all 和 ptype_base 里的网络层数据报类型,把数据报递交给不同的网络层协议的接收函数(INET域中主要是ip_rcv和arp_rcv)。该函数主要就是调用第三层协议的接收函数处理该skb包,进入第三层网络层处理。
1.2.2 网络层
IP 层的入口函数在 ip_rcv 函数。该函数首先会做包括 package checksum 在内的各种检查,如果需要的话会做 IP defragment(将多个分片合并),然后 packet 调用已经注册的 Pre-routing netfilter hook ,完成后最终到达 ip_rcv_finish 函数。
ip_rcv_finish 函数会调用 ip_router_input 函数,进入路由处理环节。它首先会调用 ip_route_input 来更新路由,然后查找 route,决定该 package 将会被发到本机还是会被转发还是丢弃:
如果是发到本机的话,调用 ip_local_deliver 函数,可能会做 de-fragment(合并多个 IP packet),然后调用 ip_local_deliver 函数。该函数根据 package 的下一个处理层的 protocal number,调用下一层接口,包括 tcp_v4_rcv (TCP), udp_rcv (UDP),icmp_rcv (ICMP),igmp_rcv(IGMP)。对于 TCP 来说,函数 tcp_v4_rcv 函数会被调用,从而处理流程进入 TCP 栈。
如果需要转发 (forward),则进入转发流程。该流程需要处理 TTL,再调用 dst_input 函数。该函数会 (1)处理 Netfilter Hook (2)执行 IP fragmentation (3)调用 dev_queue_xmit,进入链路层处理流程。
1.2.3 传输层 (TCP/UDP)
传输层 TCP 处理入口在 tcp_v4_rcv 函数(位于 linux/net/ipv4/tcp ipv4.c 文件中),它会做 TCP header 检查等处理。
调用 _tcp_v4_lookup,查找该 package 的 open socket。如果找不到,该 package 会被丢弃。接下来检查 socket 和 connection 的状态。
如果socket 和 connection 一切正常,调用 tcp_prequeue 使 package 从内核进入 user space,放进 socket 的 receive queue。然后 socket 会被唤醒,调用 system call,并最终调用 tcp_recvmsg 函数去从 socket recieve queue 中获取 segment。
1.2.4 接收端 - 应用层
每当用户应用调用
read 或者 recvfrom 时,该调用会被映射为/net/socket.c 中的 sys_recv 系统调用,并被转化为 sys_recvfrom 调用,然后调用 sock_recgmsg 函数。
对于 INET 类型的 socket,/net/ipv4/af inet.c 中的 inet_recvmsg 方法会被调用,它会调用相关协议的数据接收方法。
对 TCP 来说,调用 tcp_recvmsg。该函数从 socket buffer 中拷贝数据到 user buffer。
对 UDP 来说,从 user space 中可以调用三个 system call recv()/recvfrom()/recvmsg() 中的任意一个来接收 UDP package,这些系统调用最终都会调用内核中的 udp_recvmsg 方法。
1.2.5 报文接收过程简单总结2. Linux sk_buff struct 数据结构和队列(Queue)2.1 sk_buff(本章节摘选自 ) 2.1.1 sk_buff 是什么当网络包被内核处理时,底层协议的数据被传送更高层,当数据传送时过程反过来。由不同协议产生的数据(包括头和负载)不断往下层传递直到它们最终被发送。因为这些操作的速度对于网络层的表现至关重要,内核使用一个特定的结构叫 sk_buff, 其定义文件在 skbuffer.h。Socket buffer被用来在网络实现层交换数据而不用拷贝来或去数据包 –这显著获得速度收益。
sk_buff 是 Linux 网络的一个核心数据结构,其定义文件在 skbuffer.h。
socket kernel buffer (skb) 是 Linux 内核网络栈(L2 到 L4)处理网络包(packets)所使用的 buffer,它的类型是 sk_buffer。简单来说,一个 skb 表示 Linux 网络栈中的一个 packet;TCP 分段和 IP 分组生产的多个 skb 被一个 skb list 形式来保存。
struct sock 有三个 skb 队列(sk_buffer queue),分别是 rx , tx 和 err。
它的主要结构成员:struct sk_buff {
# packet 可以存在于 list 或者 queue 中,这两个成员用于链表处理
struct sk_buff
struct sk_buff
struct sk_buff_head
*list; #该 packet 所在的 list
struct sock
#跟该 skb 相关联的 socket
# packet 发送或者接收的时间,主要用于 packet sniffers
struct net_device
#这三个成员跟踪该 packet 相关的 devices,比如接收它的设备等
struct net_device
struct net_device
#指向各协议层 header 结构
struct tcphdr
struct udphdr
struct icmphdr
struct igmphdr
struct iphdr
struct ipv6hdr
unsigned char
struct iphdr
struct ipv6hdr
struct arphdr
unsigned char
unsigned char
* #指向该 packet 的路由目的结构,告诉我们它会被如何路由到目的地
# SKB control block,用于各协议层保存私有信息,比如 TCP 的顺序号和帧的重发状态
unsigned int
len, #packet 的长度
# MAC header 长度
# packet 的 checksum,用于计算保存在 protocol header 中的校验和。发送时,当 checksum offloading 时,不设置;接收时,可以由device计算
unsigned char
local_df, #用于 IPV4 在已经做了分片的情况下的再分片,比如 IPSEC 情况下。
cloned:1, #在 skb 被 cloned 时设置,此时,skb 各成员是自己的,但是数据是shared的
#用于支持 TSO
pkt_type, #packet 类型
ip_ # 网卡能支持的校验和计算的类型,NONE 表示不支持,HW 表示支持,
__u32 #用于 QoS
unsigned short
protocol, # 接收 packet 的协议
2.1.2 skb 的主要操作(1)分配 skb = alloc_skb(len, GFP_KERNEL) (2)添加 payload (skb_put(skb, user_data_len))(3)使用 skb-&push 添加 protocol header,或者 skb-&pull 删除 header2.2 Linux 网络栈使用的驱动队列 (driver queue)
2.2.1 队列在 IP 栈和 NIC 驱动之间,存在一个 driver queue (驱动队列)。典型地,它被实现为 FIFO ring buffer,简单地可以认为它是固定大小的。这个队列不包含 packet data,相反,它只是保存 socket kernel buffer (skb)的指针,而 skb 的使用如上节所述是贯穿内核网络栈处理过程的始终的。该队列的输入时 IP 栈处理完毕的 packets。这些packets 要么是本机的应用产生的,要么是进入本机又要被路由出去的。被 IP 栈加入队列的 packets 会被网络设备驱动(hardware driver)取出并且通过一个数据通道(data bus)发到 NIC 硬件设备并传输出去。在不使用 TSO/GSO 的情况下,IP 栈发到该队列的 packets 的长度必须小于 MTU。2.2.2 skb 大小 - 默认最大大小为 NIC MTU 绝大多数的网卡都有一个固定的最大传输单元(maximum transmission unit, MTU)属性,它是该网络设备能够传输的最大帧(frame)的大小。对以太网来说,默认值为 1500 bytes,但是有些以太网络可以支持巨帧(jumbo frame),最大能到 9000 bytes。在 IP 网络栈内,MTU 表示能发给 NIC 的最大 packet 的大小。比如,如果一个应用向一个 TCP socket 写入了 2000 bytes 数据,那么 IP 栈需要创建两个 IP packets 来保持每个 packet 的大小等于或者小于 1500 bytes。可见,对于大数据传输,相对较小的 MTU 会导致产生大量的小网络包(small packets)并被传入 driver queue。这成为 IP 分片 (IP fragmentation)。下图表示 payload 为 1500 bytes 的 IP 包,在 MTU 为 1000 和 600 时候的分片情况:备注:
以上资料是从网络上获取的各种资料整理而来
这一块本身就比较复杂,而且不同的 linux 内核的版本之间也有差异,文中的内容还需要进一步加工,错误在所难免。
作者信息:刘世民(Sammy Liu),IBM 云架构师,十余年IT行业从业经历,在电信、企业软件、存储以及云计算等领域做过研发、管理和架构设计等工作。从 2012 年开始学习 OpenStack,对其核心模块有较深入的了解;带领过团队开发OpenStack模块。
责编:陈晨 欢迎投稿,chenchenjs#csdn.net
日-23日,由CSDN重磅打造的将在深圳举行,目前18位讲师和议题已全部确认。两场峰会大牛讲师来自百度、腾讯、阿里、京东、小米、唯品会、滴滴出行、携程等知名互联网公司,共同探讨高可用/高并发/高稳定/高流量的系统架构设计、秒杀系统架构、搜索架构、中小企业架构之道、数据平台系统演进历程和技术剖析、传统数据库与分布式数据库选型/备份/恢复原理及优化实践、大数据应用实战等领域的热点话题与技术。【目前限时6折,】}

我要回帖

更多关于 socket接收xml报文 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信