基于golang实现的376.1规约采集前置程序

2 篇文章 0 订阅
1 篇文章 0 订阅

go3761

       https://github.com/jonenine/go3761
       实现了稳定而高效的网络通讯层和灵活的规约配置层,可作为物联网行业部署在云端的采集前置程序的原型。

    网络层架构

       网络层分为io goroutine和worker goroutine,有点类似于netty的网络模型。当accept连接之后就启动一个goroutine来接收数据,一旦接收到数据,goroutine退出,同时将handler连同数据(事件)通过channel发给worker进行处理,在一个固定数量的worker group(池)内进行解帧和其他业务处理。处理之后再启动一个新的goroutine来接收数据。

       以前采取io goroutine同时接收数据和处理数据的做法,虽然性能也不错。发现一段时间后golang的后台线程疯狂增加,而采用这种类似于reactor的模式不但提高了性能,也克服了后台线程飞涨的问题。

    性能测试

       性能测试结果还是不错的:

       在windows上似乎很难突破c10k后性能急剧下降的限制,并发数超过1万是没问题(可以并发连接到到很大),但并发超过1万后性能急剧下降,比如并发1万1千和并发一万的性能差距相当大。应该是操作系统的问题引起的,我用的server2008R2 enterprise。

       在linux上性能就好了很多,以下是测试数据

       硬件配置

       联想低配服务器

       8 核心Intel® Xeon® CPU E3-1230 v6 @ 3.50GHz

       内存32G

       软件环境

       Redhat6.8

       golang1.12.5

       在单节点上轻松实现c50k,

       5万客户端不停发送测试报文,服务端每秒40万次解帧,

       从proc/xxxx/status看,线程数19个,内存占用(vmRss)保持在420M左右

       资源控制的相当好,程序也很稳定。

       因为测试客户端和server在同一台机器上,cpu已经基本压满。单台服务器的测试客户端数量(端口数)也不可能突破6万,条件所限没有继续测试下去。不过,就测试程序的轻松表现来看。在生产环境下应该可以轻松实现c100k。

       本程序只是实现了376.1规约的解帧,实现了网路层框架而已。而实际的采集程序业务要复杂的多。本程序可以作为golang前置机的原型程序。相信在这个原型基础上可以作出高性能的成熟稳定的golang前置采集程序。

    关键数据类型

       ByteBuf

       在按照某种规约或约定解析tcp的字节流的时候,往往会出现错误的模式匹配。比如你规定了业务帧的帧头为某些按顺序出现的byte常量,但这个常量组合也极有可能出现在非帧头的部分。当发现匹配失败了之后,通常需要向前回溯。

       而java netty的ByteBuf就拥有markReaderIndex,resetReaderIndex方法,可以在解析的时候做标记,发现匹配错误之后可以回到标记的位置。

       ItemConfig和Frame3761Config

       ItemConfig是一种通用的帧结构解析配置方式。将规约帧结构的每一个数据段都用ItemConfig来进行配置,每个ItemConfig定义一个帧结构段(其实就是各种数据域,如长度域、控制域)的长度,验证,输出,是否计算校验和等几个部分。Frame3761Config数组再将所有的帧结构段组合起来成为完整的帧结构。

       解析方法ReadFrame3761,采取非常谨慎的容错策略,当解析到某个规约项配置的validate方法失败后,程序会回溯到当前认为的帧头的下一个字节去重新匹配帧头。这样可以从数据流中更加有效的识别帧结构。

       解析程序可以非常轻松的移植到其他规约上去。每一帧结构段的配置都可以单独进行测试和调试。在可维护性和可移植性上远胜于原来将解帧的工作集中到一个方法或一个类中的写法,在性能上也没有明显的下降。

       解析方法ReadFrame3761并非和376规约耦合,可以不用修改的移植到其他规约的解析程序中,需要修改的是规约配置部分。待golang将来支持泛型之后,程序的可读性和扩展性还会得到很大改善。

    类图

在这里插入图片描述
    时序图

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现802.1x认证功能的最常用的方式是通过EAP协议(Extensible Authentication Protocol)进行认证。以下是一个简单的golang代码示例,用于实现基于EAP的802.1x认证功能。 ```go package main import ( "crypto/tls" "fmt" "net" "bytes" "encoding/binary" ) const ( EAPCodeRequest = 1 EAPCodeResponse = 2 EAPCodeSuccess = 3 EAPCodeFailure = 4 ) const ( EAPTypeIdentity = 1 EAPTypeMD5Challenge = 4 ) func main() { // 连接认证服务器 conn, err := tls.Dial("tcp", "auth-server:1812", nil) if err != nil { fmt.Println(err) return } defer conn.Close() // 生成EAP Request Identity包 reqIdPacket := generateEapPacket(EAPTypeIdentity, EAPCodeRequest, []byte{}) conn.Write(reqIdPacket) // 接收EAP Response Identity包 resIdPacket := make([]byte, 1024) len, err := conn.Read(resIdPacket) if err != nil { fmt.Println(err) return } // 解析EAP Response Identity包 resIdType := binary.BigEndian.Uint16(resIdPacket[18:20]) resIdData := resIdPacket[20:len] if resIdType != EAPTypeIdentity || len <= 20 { fmt.Println("Invalid EAP Response Identity packet") return } // 发送EAP Request MD5-Challenge包 reqMd5Packet := generateEapPacket(EAPTypeMD5Challenge, EAPCodeRequest, resIdData) conn.Write(reqMd5Packet) // 接收EAP Response MD5-Challenge包 resMd5Packet := make([]byte, 1024) len, err = conn.Read(resMd5Packet) if err != nil { fmt.Println(err) return } // 解析EAP Response MD5-Challenge包 resMd5Type := binary.BigEndian.Uint16(resMd5Packet[18:20]) resMd5Data := resMd5Packet[20:len] if resMd5Type != EAPTypeMD5Challenge || len <= 20 { fmt.Println("Invalid EAP Response MD5-Challenge packet") return } // 认证成功 successPacket := generateEapPacket(0, EAPCodeSuccess, []byte{}) conn.Write(successPacket) fmt.Println("Authentication succeeded") } func generateEapPacket(eapType uint8, eapCode uint8, eapData []byte) []byte { buf := new(bytes.Buffer) binary.Write(buf, binary.BigEndian, uint8(0)) // EAP Version binary.Write(buf, binary.BigEndian, eapCode) // EAP Code binary.Write(buf, binary.BigEndian, uint16(5+len(eapData))) // EAP Packet Length binary.Write(buf, binary.BigEndian, uint8(eapType)) // EAP Type binary.Write(buf, binary.BigEndian, uint8(0)) // EAP Identifier binary.Write(buf, binary.BigEndian, uint16(len(eapData))) // EAP Data Length binary.Write(buf, binary.BigEndian, eapData) // EAP Data return buf.Bytes() } ``` 以上代码连接到认证服务器,并使用EAP Identity和EAP MD5-Challenge协议进行认证。如果认证成功,将发送EAP Success包,如果认证失败,将发送EAP Failure包。 需要注意的是,以上代码只是一个简单的示例,实际的802.1x认证通常比这复杂得多。在实际应用中,您需要根据您的网络环境和认证服务器的要求进行相应的调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值