看看我写的DSL(1)-数据包创建
fineqtbull
2009-11-14
正在用Scala开发一个开源协议测试软件,准备尝试一下DSL的开发,在这里晒晒阶段开发成果。学Scala开发不久,不保证这是DSL的最好设计,仅供大家参考和讨论。
//创建数据包(ICMP Echo Request) val pingRequest = ^^^("EtherProtocol") { ^^("EtherProtocol") { ^("dstAddress") = AS("11:22:33:44:55:66", MAC_ADDRESS) ^("srcAddress") = AS("22:22:33:44:55:66", MAC_ADDRESS) ^("etherType") = 0x0800 ^("payload") { ^("ipv4") { ^("header") { ^("identification") = 1 ^("timeToLive") = 255 ^("protocol") = 1 ^("sourceAddress") = AS("192.168.1.1", IPV4_ADDRESS) ^("destinationAddress") = AS("192.168.1.2", IPV4_ADDRESS) ^("options") { ^(0) { ^("security") { ^("security" ) = 0x789A } } ^(1) { ^("lssr") { ^("pointer" ) = 100 } } } } ^("payload") { ^("icmpv4") { ^("echoRequest") { ^("identifier") = 100 ^("sequenceNumber") = 1000 ^("data") = OS("01020304") } } } } } } } //打印 ValueDumper.dump(pingRequest) 执行结果: 0:66 EtherProtocol.EtherProtocol 0:6 dstAddress 11:22:33:44:55:66 6:6 srcAddress 22:22:33:44:55:66 12:2 etherType 2048 IPv4 14:48 payload 14:48 ipv4 Ipv4Protocol.Ipv4Protocol 14:48 Ipv4Protocol.Ipv4Protocol 14:36 header 14:1 0000---- 4 version 0xF0 14:1 ----0000 0 headerLength 0x0F 15:1 typeOfService '00000000'B 16:2 totalLength 0 18:2 identification 1 20:1 0--------------- 0 reserved 0x8000 20:1 -0-------------- false doNotFrag 0x4000 20:1 --0------------- false moreFrags 0x2000 20:2 ---0000000000000 0 fragmentOffset 0x1FFF 22:1 timeToLive 255 23:1 protocol 1 ICMP: Internet Control Message Protocol 24:2 hcs '0000'O 26:4 sourceAddress 192.168.1.1 30:4 destinationAddress 192.168.1.2 34:16 options 34:12 [0] 34:12 security 34:1 optionType 130 35:1 optionLength 0 36:2 security 30874 EFTO 38:2 compartments 0 40:2 handling 0 42:3 tcc 0 45:1 nop 1 46:4 [1] 46:4 lssr 46:1 optionType 131 47:1 optionLength 0 48:1 pointer 100 49:0 routeData 49:1 nop 1 50:12 payload 50:12 icmpv4 Icmpv4Protocol.Icmpv4Protocol 50:12 Icmpv4Protocol.Icmpv4Protocol 50:12 echoRequest 50:1 icmpType 8 51:1 icmpCode 0 52:2 checksum '0000'O 54:2 identifier 100 56:2 sequenceNumber 1000 58:4 data '01020304'O 62:4 fcs '00000000'O |
|
night_stalker
2009-11-14
这些 ^ 太奇怪了 …… 还比不上老老实实赋值简洁平白 ……
val pingRequest = new EtherProtocol() { dstAddress = MAC("11:22:33:44:55:66") srcAddress = MAC("22:22:33:44:55:66") etherType = 0x0800 payload = new Ipv4() { ... } } |
|
fineqtbull
2009-11-14
night_stalker 写道 这些 ^ 太奇怪了 …… 还比不上老老实实赋值简洁平白 ……
val pingRequest = new EtherProtocol() { dstAddress = MAC("11:22:33:44:55:66") srcAddress = MAC("22:22:33:44:55:66") etherType = 0x0800 payload = new Ipv4() { ... } } ,这种方案我也考虑过,而且在性能上也会好一点,还可以靠编译器来检查字段名称正确与否,不过要另外生成Scala类,所以暂时还不会实现。直接用^("字段名")格式是由于协议格式已经以别的文本形式定义了,所以不用生成Scala类直接用字段名就可以了,觉得会方便一点。下面是Ethernet协议的定义: module EtherProtocol { import from BasicTypeAndValues { type Oct6, UInt16, Oct4, MacAddress } import from Ipv4Protocol { type Ipv4Protocol } import from ArpProtocol { type ArpProtocol } import from GlobalEnumSets { enumset EtherTypes } import from Ipv6Protocol { type Ipv6Protocol } type record EtherProtocol { MacAddress dstAddress, MacAddress srcAddress, UInt16 etherType, EtherPayload payload, Oct4 fcs optional } with { variant Protocol(true); PushEmptyField([DECODE], "etherType") variant(etherType) SetField([DECODE]) enumref(etherType) EtherTypes } type union EtherPayload { Ipv4Protocol ipv4, ArpProtocol arp, Ipv6Protocol ipv6, octetstring data } with { variant CaseRef("-etherType", #UInt16); CaseDefault(data) variant(ipv4) CaseCond(UInt16 (0x0800)) variant(arp) CaseCond(UInt16 (0x0806)) variant(ipv6) CaseCond(UInt16 (0x86DD)) } } with { encode "FPB" variant ByteOrder(BIG_ENDIAN) } PS:本来想用#的,不过#是关键字所以选了^。另外^^^、^^、^分别表示模块、类型、字段。 |
|
matt.u
2009-11-17
^^^太不直观了。
|
|
fineqtbull
2009-11-17
matt.u 写道 ^^^太不直观了。
主要是考虑到模块、类型、字段的层次关系,字段用得最多,如果用“field”等字符输入会挺麻烦,所以用了一个符号^。而根据层次关系,由此得来了^^和^^^。上来可能有点怪.... |