本文将对TCP/IP的数据收发做一个粗略总结~
1、TCP/IP基本特点
TCP/IP总的设计目的就是保证数据的快速有序的传输,且无丢失,基本特点如下:
- 面向连接:两端组成一个连接,每端以五元组为标识
- 双工字节流: 采用字节流进行双工数据通信
- 有序发送:利用序列号保证发送的有序性
- 可靠性:利用ACK保证数据的可靠性
- 流控:接收方利用接收窗口通告发送方
- 拥塞控制:接收方利用拥塞窗口通告发送方
2、报文发送过程
TCP/IP网络协议栈包含多个层次,下图以一个TCP连接中的报文发送过程简述其基本流程:
- 用户层创建数据,调用write系统调用发送数据。
- 一旦执行系统调用,系统则进入内核层。对于类Linux系统,通过文件描述符关联socket和应用,内核中socket包含收发两块buffer。
- 在系统调用执行数据将被拷贝至内核memory当中,然后添加至发送buffer尾部,即按序发送。
- 在TCP层,TCB(TCP Control Block) 关联socket,如果TCP允许数据发送,内核创建TCP segment。否则,由于规则或者流量控制会将该报文丢弃。至于TCP segment报文格式,无外乎一个header加payload,还有个checksum。TCP校验和往往由网卡进行计算。
- 继续在TCP segment上封装IP层,再算下IP校验和,就可以扔给网络层了,比如以太网层。
- 以太网层开始查找下一跳IP的MAC地址,一旦完成将继续封装Etherent头,最终送往driver层,这里往往也是各大抓包工具进行数据拷贝的地方,比如tcpdump/wirshark,或者是自己写的抓包工具;流量整形也往往在这一层完成。
- driver层在收到发送请求之后,通过DMA将该主存中的数据拷贝至内部RAM之中。在数据拷贝中,同时加入符合以太网协议的相关header,IFG、前导符和CRC。对于以太网网络,物理层发送采用CSMA/CD,即在发送过程中侦听链路冲突;而对于Wi-Fi网络,则采用CSMA/CA,其基本思想是要想占用channel并发言,首先做好聆听(也是做人哲学之一),对于需要ACK的报文,一旦在规定时间内搜不到ACK,则重传该报文。
- 一旦网卡完成报文发送,将产生中断通知CPU。
对于报文发送过程而言,上层协议栈是生产者,驱动层为消费者。
下面以无线网卡驱动为例详述整个报文发送流程的实现细节:
- 上层协议栈(三层及以上)和驱动层之间的数据传递采用队列,一个网络接口绑定一个三层报文发送队列。802.11 MAC层从网络接口的发送队列中拿到三层报文,添加LLC层和802.11 header,此时二层报文已经组好。
- 驱动层同样采用一个二层报文发送队列,可以将上一步组好的二层报文放入该队列。驱动的任务就是把二层报文送入无线网卡的硬件FIFO,最终转为射频信号发送。软硬件交互通过一个循环缓冲区完成,具体而言,首先主存中定义一个TX Ring,包括多个TFD(发送描述符),其中一个TFD可以由多个TB(发送缓冲区)组成,里面除了包含要发送的数据,还包含了发送相关的控制信息;数据在DRAM和硬件FIFO之间的搬迁由DMA完成,搬迁的数量通过TX Ring的两个指针完成,一个是写指针,由软件更新,告诉硬件我已经把这个位置的TFD准备好,你可以拿了,另一个是读指针,由硬件拿走数据后更新该指针,通过中断告诉软件我已经取走数据,你可以继续在该TFD上更新数据。
3、报文的接收过程
- 网卡对报文进行CRC检查,如果合法就写入主存(一般通过DMA完成)。一旦完成写入,网卡发送中断通知CPU。
- 驱动层对报文进行检查,在发送至上层协议栈之前,必须封装成OS相关的数据结构,比如Linux对应sk_buff,BSD对应mbuf。
- 以太网层同样对报文进行合法性检查,然后发送至网络层,交给不同的协议处理模块,对于IP报文交给IP层,而对于ARP报文则送至ARP模块。
- IP层继续检查报文合法性,判断其是进行IP路由还是本地处理。根据IP头的协议字段,上发至上层,比如6对应TCP层。
- TCP层同样检查TCP检验和,往往由网卡计算完成,而不是内核。
- 以TCP报文的五元组作为关键字进行连接查找,查看是否匹配该层的规则,如果符合,则加入接收缓冲区。
4、不是结束语
理解问题需从根上抓起,TCP/IP也一样,仍有许多细节需要在工作实践中反复体会。