对于网络通信程序的调试,我们一般是这样进行的:
客户端 服务器端
打印发送数据
|
使用socket发送数据 --------------> 使用socket接受数据
| |
字节数) 打印接收到的数据
测试方法,需要对程序添加打印代码,并且每次改动调试信息时,都需要重新编译程序,较为繁琐,效率低。为了查看数据包的内容,我们需要做很多的打印操作,并且还要在log中通过关键字来查找打印的内容。
Wireshark是网络抓包,并对包进行分析的软件。通过调用pcap库,它可按照我们的需求,抓取各种数据包。
协议进行解包,能够在窗口中清晰的看到通信协议中每个段的值。但是当我们使用自己的通信协议时,wireshark只能识别到TCP/UDP协议,我们的数据内容无法识别,只能在窗口中的Data段中显示原始数据,我以前都是能通过偏移,来与自己程序中的数值进行一一比较,以检测自己的程序所发送的数据是否正确。
云胀ǖ耐ㄐ判榻薪獍2榭词褂檬植幔唬诘谑隆盠ua Support in Wireshark“中有对此功能的描述。只要用lua写一个脚本,并在程序启动时调用即可(这些,在手册中都有说明)。
举个例子,假如我们使用结构体进行通信,众多消息结构体中,有如下一个:
写一个lua脚本来解析包中的这部分内容(假设我们使用UDP协议,12000端口):
复制代码
1. do local p_student = Proto("student","student message");
2. -- 创建三个字段,其中,第一个参数为解析时使用的,第二个参数为在窗口中显示的名称,第三个参数(如果有的话)为数据类型。 local f_name = ProtoField.string("student.name", "Name") local f_age = ProtoField.uint32("student.age", "Age", base.DEC) local f_grade = ProtoField.uint32("student.grade", "Grade", base.DEC)
3.
4. p_student.fields = { f_name, f_age, f_grade }
5.
6. local data_dis = Dissector.get("data")
7.
8. -- 解析数据包时的函数,类似C语言中的回调函数 function p_student.dissector(buf, pkt, root) local t = root:add(p_iplb, buf(0, 24)) -- udp数据部分的前24个字节,使用student协议解析 t:add(f_name, buf(0,16)) -- 0-16是student.name字段 t:add(f_age, buf(16, 4)) -- 16-20是student.age字段 t:add(f_grade, buf(20, 4)) -- 20-24是student.grade字段
9.
10. data_dis:call(buf(40):tvb(), pkt, root) -- 如果还有剩余数据,作为一般的Data段进行解析 end
11.
12. -- 添加协议及端口号的关联,当遇到符合条件的数据包,wireshark将自动按照此协议进行解析 local udp_encap_table = DissectorTable.get("udp.port") udp_encap_table:add(12000, p_iplb) -- 12000为我们所使用的端口号
13. end
|
示例脚本中用到了wireshark所提供的API函数,更多信息和函数说明,可参考wireshark自带的使用说明。