之前做过一个深交所股票数据的接存储软件,消息的协议是这样。

协议文档在这  https://wenku.baidu.com/view/d102cd0b4a73f242336c1eb91a37f111f1850df2.html

由于socket接受来的数据会出现粘包或者半包的情况。所以要进行拆包处理代码是这样的,但是无论网络状态是否稳定都会出现丢包的情况。

  private RecMessage TryReadAmessage(ref byte[] bytes)
{
if (bytes.Length < )
return null;
var msgType = NetworkBitConverter.ToInt32(bytes, );
if (messageTypes.Contains(msgType))
{ var msgLength = NetworkBitConverter.ToInt32(bytes, );
if (msgLength >= && msgLength < )
{
if (bytes.Length < (msgLength + ))
return null; var outputByte = new byte[ + msgLength];
Array.Copy(bytes, outputByte, msgLength + );
bytes = bytes.Removebytes(msgLength + );
var chkbyte = new byte[];
Array.Copy(outputByte, msgLength + , chkbyte, , );
if (!GetBytesFomObj.CheckSum(chkbyte, outputByte)) return null; return new RecMessage
{
MessageType = msgType,
MessageLenght = msgLength,
MessageContent = outputByte.Removebytes()
};
}
else
bytes = bytes.Removebytes();
}
else
bytes = bytes.Removebytes();
return null;
}

后来用了supersocket框架拆包,效果不错,基本没有发现错误包的情况。看代码

  public class ClientBinaryFilter : FixedHeaderReceiveFilter<RecMessage>
{
/// <summary>
/// 所有消息类型
/// </summary>
private readonly int[] _messageTypes = new int[]
{ ,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
, };
public ClientBinaryFilter() : base()
{ }
private int key;
private int datalength;
protected override int GetBodyLengthFromHeader(IBufferStream bufferStream, int length)
{
key = bufferStream.ReadInt32(false);
datalength = bufferStream.ReadInt32(false);
return datalength + ;
} public override RecMessage ResolvePackage(IBufferStream bufferStream)
{
var buffer = new byte[datalength + ];
bufferStream.Skip().Read(buffer, , datalength + );
return new RecMessage
{
MessageType = key,
MessageLenght = datalength,
MessageContent = buffer
};
}
}

后来学习了golang语言,感觉非常适合做这种实时性很高的软件。由于逻辑不是特别复杂,没有用到所有的golang的特性,知识点有:net(socket),goruntime,channel(缓冲),数组切片slice,互斥锁sync.Mutex,redigo(redis),ffjson(序列化与反序列化)

核心的代码在这里

 //socket接受函数
func handMsgChannel(con net.Conn) {
con.Write(SendLogOn())
go sendHeartBt(con)
var unCompleteBytes []byte
for {
//startTime := time.Now()
buffer := make([]byte, )
readLength, err := con.Read(buffer)
CheckError(err, con)
if readLength > {
var readBuf []byte = buffer[:readLength]
//获取上次为解析的半包并装载到此次循环中解析
if len(unCompleteBytes) != {
readBuf = lib.BytesCopy(unCompleteBytes, readBuf)
}
readMessageChannel(&readBuf) //拆包分解,并把半包数据留在下次循环处理
unCompleteBytes = readBuf
//endTime := time.Since(startTime)
//fmt.Println("读取并数据处理时间: ", endTime)
}
}
} //利用channel读取并传入channel
func readMessageChannel(input *[]byte) {
//var output []BaseMsgModel
for {
byteArray := *input
//头+长度+校验 最小12个字节,不足跳出
if len(byteArray) < {
break
}
mt := lib.BytesToInt32(byteArray[:])
//获取数据头
if lib.Contain(mt, MsgTypes) {
ml := lib.BytesToInt32(byteArray[:])
//数据长度
if ml >= && ml < {
if len(byteArray) < +int(ml) {
break
}
//获取报文content
mc := byteArray[ : +int(ml)]
sum := lib.BytesToInt32(mc[len(mc)- : len(mc)])
checksum := lib.CheckSum(byteArray[ : +int(ml)])
//检查校验
if checksum == sum {
model := &BaseMsgModel{
mt,
ml,
mc,
}
chmsg <- model
*input = byteArray[+int(ml):]
} else {
*input = byteArray[+int(ml):]
fmt.Println("错误数据")
}
} else {
//错误长度移除
*input = byteArray[:]
fmt.Println("错误长度")
}
} else {
//错误头部移除
*input = byteArray[:]
fmt.Println("错误头")
}
}
} //分发存储channel中数据
func translateMsgChannel() {
for {
item := <-chmsg
//fmt.Print("数据类型", msgs.MsgType, "数据长度", msgs.MsgLength, msgs.MsgContent, "\r\n")
switch item.MsgType {
case :
msg.Save300111(item.MsgContent)
systemParams.Params.Lock()
systemParams.msg300111Length++
systemParams.Params.Unlock()
break
case :
msg.Save309011(item.MsgContent)
systemParams.Params.Lock()
systemParams.msg309011Length++
systemParams.Params.Unlock()
break
default:
break
}
systemParams.Params.Lock()
systemParams.RecLength++
systemParams.Params.Unlock()
}
}

经测试后不禁感叹golang真是黑科技,.net的代码内存会达到50M以上,CPU10%左右(I5 4核4线程)

golang呢10M左右 CPU 0.5%~1%,golang。。。牛啊!

代码在这  https://gitee.com/siming.liu/golang_stock

记一次golang的实践的更多相关文章

  1. Golang Gin实践 番外 请入门 Makefile

    Golang Gin实践 番外 请入门 Makefile 原文地址:Golang Gin实践 番外 请入门 Makefile 前言 含一定复杂度的软件工程,基本上都是先编译 A,再依赖 B,再编译 C ...

  2. Golang 高效实践之并发实践

    前言 在我前面一篇文章Golang受欢迎的原因中已经提到,Golang是在语言层面(runtime)就支持了并发模型.那么作为编程人员,我们在实践Golang的并发编程时,又有什么需要注意的点呢?下面 ...

  3. Golang 高效实践之并发实践context篇

    前言 在上篇Golang高效实践之并发实践channel篇中我给大家介绍了Golang并发模型,详细的介绍了channel的用法,和用select管理channel.比如说我们可以用channel来控 ...

  4. Golang高效实践之泛谈篇

    前言 我博客之前的Golang高效实践系列博客中已经系统的介绍了Golang的一些高效实践建议,例如: <Golang高效实践之interface.reflection.json实践>&l ...

  5. 知乎社区核心业务 Golang 化实践 - 知乎 https://zhuanlan.zhihu.com/p/48039838

    知乎社区核心业务 Golang 化实践 - 知乎 https://zhuanlan.zhihu.com/p/48039838

  6. 记一次golang内存泄露

    记一次golang内存泄露 最近在QA环境上验证功能时,发现机器特别卡,查看系统内存,发现可用(available)内存仅剩200多M,通过对进程耗用内存进行排序,发现有一个名为application ...

  7. 【GoLang】golang 最佳实践汇总

    最佳实践 1 包管理 1.1 使用包管理对Golang项目进行管理,如:godep/vendor等工具 1.2 main/init函数使用,init函数参考python 1.2.1 main-> ...

  8. Golang 高效实践之defer、panic、recover实践

    前言 我们知道Golang处理异常是用error返回的方式,然后调用方根据error的值走不同的处理逻辑.但是,如果程序触发其他的严重异常,比如说数组越界,程序就要直接崩溃.Golang有没有一种异常 ...

  9. 记一次golang的内存泄露

    程序功能 此程序的主要功能是将文件中数据导入到clickhouse数据库中. [问题描述] 服务器内存每隔一段时间会耗尽 [问题分析] 由于使用的是go语言开发的,所以采用了业界流行的工具pprof. ...

随机推荐

  1. VB 共享软件防破解设计技术初探(一)

    VB 共享软件防破解设计技术初探(一) ×××××××××××××××××××××××××××××××××××××××××××××× 其他文章快速链接: VB 共享软件防破解设计技术初探(二)http ...

  2. scrollLeft滚动(用animate替代)

    原: let checkedLeft1 = $('#dateBox').find('.checked').position().left let checkedLeft2 = $('#dateBox' ...

  3. UNITY中的MOUSE点击事件的判断和AS3中的异同

    UNITY - 在UPDATE中轮询检测 Update() { if(Input.GetButton("Fire1") } AS3 - 事件监听 addEventListener. ...

  4. Dom对象总结介绍&事件介绍&增删查找标签

    1.dom有5个属性,属性内容如下 下面开始介绍Dom属性,一共有5个属性 1.document object:文档对象 2.element object:标签对象 3.test object:文本对 ...

  5. 矩形最小路径和 · Minimum Path Sum

    [抄题]: 给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径. [思维问题]: [一句话思路]: 和数字三角形基本相同 [输入量]:空: 正常情况:特大:特小:程序里 ...

  6. golang实现任务分发处理

    package main import ( "flag" "fmt" "os" "log" "net/http ...

  7. Vagrant WinNFSd

    Vagrant WinNFSd Manage and adds support for NFS on Windows. Supported Platforms As of version 1.0.6 ...

  8. boost 学习(1)

    智能指针的学习 中文教程网站 http://zh.highscore.de/cpp/boost/ 不过代码可能 由于BOOST 版本不同需要稍作修改 scoped_ptr 离开作用域则自动调用类析构函 ...

  9. msys2 设置home路径为windows用户路径

    1配置/etc/nsswitch.conf db_home: windows 2(可不配)增加windows环境变量HOME为%USERPROFILE% 3(可不配)ssh默认仍使用msys中的hom ...

  10. mysql 1045 access denied for user********

    另一个方法Windows: 1. 管理员登陆系统,停止mysql服务或者结束mysqld-nt进程2. 进入命令行,来到mysql的安装目录.假设安装目录为 d:/mysql/ , CMD进入命令行3 ...