DIY TCP/IP 网络设备模块6

上一篇:DIY TCP/IP 网络设备模块5
介绍DIY TCP/IP网络设备模块之上的其他模块的实现之前,本节先来完成log的分级打印。5.3.4节运行结果的打印输出已经相对复杂,目前DIY TCP/IP的log均是通过printf打印到标准输出,上层模块实现之后会有更多的log输出。避免过多的打印信息,实现log的分级打印。本节引入两个新的文件debug.c和debug.h,做为DIY TCP/IP的debug模块。

  #ifndef _DEBUG_H_
  #define _DEBUG_H_
  
  #define ERROR   0
  #define WARNING 1
  #define DEBUG   2
  #define VERBOSE 3
  #define DEF_DEBUG_LEVEL DEBUG
  //#define DEF_DEBUG_LEVEL VERBOSE	
 
  int log_printf(int level, const char *fmt, ...);
 
  #endif

debug.h头文件中定义了log的优先级和暴露给其他模块使用的函数接口log_printf。ERROR到VERBOSE共4个优先级,ERROR的优先级最高,VERBOSE最低。log_printf第一个参数是log优先级。将提示性的信息,例如从pcap_callback收到的链路层数据帧的长度和时间戳,设置为VERBOSE,减少log输出。出错处理的log设置为ERROR或WARNING,关键路径代码的log优先级设置为DEBUG。DEF_DEBUG_LEVEL是默认的log优先级,用于过滤较低优先级的log,默认优先级设置为DEBUG。
debug.c

  #include <stdio.h>
  #include <stdarg.h>
  
  #include "debug.h"
  
  int log_printf(int level, const char *fmt, ...)
  {
	   int ret = 0;
	   va_list ap;
	   if (level <= DEF_DEBUG_LEVEL) {
		      va_start(ap, fmt);
		      ret = vprintf(fmt, ap);
		      va_end(ap);
	   }
	   return ret;
  }

输出字符串,第三个参数是C语言中的可变参数。C语言中的printf使用可变参数的典型函数,C语言中,函数参数存放在栈空间,根据格式化输出字符串fmt的地址和长度,可以找到栈空间中存放在fmt之后的参数值。va_list是可变参数列表,通过va_start可以获取可变参数列表,其实va_start的实现可以理解为(char *)fmt + sizeof(fmt),就是fmt的地址加上fmt指针本身占用的栈空间大小,得到fmt之后第一个参数的地址。printf的实现也是通过va_start先获取参数列表,再根据fmt格式字符串中的关键字%d,%s,%f等来逐个解析参数列表。
log_printf实现原理与printf类似,先判断log优先级,只有优先级小于等于默认优先级的log,才会被输出。这样就可以过滤掉优先级为VERBOSE的log,DEBUG,ERROR和WARNING优先级的log可以正常输出。
修改Makefile

  tcp_ip_stack:device.o init.o debug.o
   gcc -o tcp_ip_stack device.o init.o debug.o -lpcap -lpthread
  device.o:device.c device.h init.h common.h
   gcc -c device.c
  init.o:init.c init.h
   gcc -c init.c
  debug.o:debug.c debug.h
   gcc -c debug.c
  clean:
   rm -rf *.o
   rm -rf tcp_ip_stack

新的debug.c和DIY TCP/IP的其他模块编译链接在一起。Makefile中,line1为tcp_ip_stack目标添加新的依赖debug.o。line 7是debug.o的依赖,debug.c和debug.h。line 8是编译生成debug.o的gcc命令。
debug模块已经实现完成,将DIY TCP/IP其他模块用到的printf均改为log_printf并赋予log优先级,不再给出具体改动细节。后续章节log打印均采用log_printf。将网络设备模块中pcap_callback函数打印链路层数据帧的时间戳和长度的log优先级改为VERBOSE,编译并运行结果如下:

  gannicus@ubuntu:~/guojia/tasks/DIY_USER_SPACE_TCPIP/ch2/2$ make
  gcc -c device.c
  gcc -c init.c
  gcc -c debug.c
  gcc -o tcp_ip_stack device.o init.o debug.o -lpcap -lpthread
  gannicus@ubuntu:~/guojia/tasks/DIY_USER_SPACE_TCPIP/ch2/2$ sudo ./tcp_ip_stack 
  [sudo] password for gannicus: 
   Network device init
  filter: ether proto 0x0800 or ether proto 0x0806
  Network device RX init
  dev rx, ethernet type: 0800, dc:33:0d:1c:50:fc --> ff:ff:ff:ff:ff:ff
  dev rx, ethernet type: 0800, 8c:a9:82:11:d1:de --> 01:00:5e:7f:ff:fa
  dev rx, ethernet type: 0800, dc:33:0d:2a:95:33 --> ff:ff:ff:ff:ff:ff
  dev rx, ethernet type: 0800, 8c:a9:82:11:d1:de --> 01:00:5e:00:00:fc
  dev rx, ethernet type: 0800, dc:33:0d:1c:50:fc --> ff:ff:ff:ff:ff:ff

编译结果显示,debug.c已经加入Makefile编译,并链接到tcp_ip_stack中,运行结果显示,网络设备模块中只有优先级为DEBUG的log被打印输出。
5.6 小结
本章实现了DIY TCP/IP 的网络设备层,定义网络设备结构体,实现接收线程,定义网络设备模块数据帧的数据结构,封装pcap_callback返回的链路层数据帧。实现了链表,队列,并基于此实现了网络设备模块的接收队列,异步处理链路层数据帧。在接收线程中解析链路层数据帧的以太网头,最后又给出了debug模块的实现。DIY TCP/IP上层模块的实现均基于网络设备模块,根据解析出的以太网头部类型,将数据帧交付给后续章节将要实现的ARP,ICMP,IP或TCP模块,进行上层协议的处理。
DIY TCP/IP end of chapter 5
下一篇:DIY TCP/IP Payload Buffer模块0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值