记一次golang的实践
之前做过一个深交所股票数据的接存储软件,消息的协议是这样。
协议文档在这 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的实践的更多相关文章
- Golang Gin实践 番外 请入门 Makefile
Golang Gin实践 番外 请入门 Makefile 原文地址:Golang Gin实践 番外 请入门 Makefile 前言 含一定复杂度的软件工程,基本上都是先编译 A,再依赖 B,再编译 C ...
- Golang 高效实践之并发实践
前言 在我前面一篇文章Golang受欢迎的原因中已经提到,Golang是在语言层面(runtime)就支持了并发模型.那么作为编程人员,我们在实践Golang的并发编程时,又有什么需要注意的点呢?下面 ...
- Golang 高效实践之并发实践context篇
前言 在上篇Golang高效实践之并发实践channel篇中我给大家介绍了Golang并发模型,详细的介绍了channel的用法,和用select管理channel.比如说我们可以用channel来控 ...
- Golang高效实践之泛谈篇
前言 我博客之前的Golang高效实践系列博客中已经系统的介绍了Golang的一些高效实践建议,例如: <Golang高效实践之interface.reflection.json实践>&l ...
- 知乎社区核心业务 Golang 化实践 - 知乎 https://zhuanlan.zhihu.com/p/48039838
知乎社区核心业务 Golang 化实践 - 知乎 https://zhuanlan.zhihu.com/p/48039838
- 记一次golang内存泄露
记一次golang内存泄露 最近在QA环境上验证功能时,发现机器特别卡,查看系统内存,发现可用(available)内存仅剩200多M,通过对进程耗用内存进行排序,发现有一个名为application ...
- 【GoLang】golang 最佳实践汇总
最佳实践 1 包管理 1.1 使用包管理对Golang项目进行管理,如:godep/vendor等工具 1.2 main/init函数使用,init函数参考python 1.2.1 main-> ...
- Golang 高效实践之defer、panic、recover实践
前言 我们知道Golang处理异常是用error返回的方式,然后调用方根据error的值走不同的处理逻辑.但是,如果程序触发其他的严重异常,比如说数组越界,程序就要直接崩溃.Golang有没有一种异常 ...
- 记一次golang的内存泄露
程序功能 此程序的主要功能是将文件中数据导入到clickhouse数据库中. [问题描述] 服务器内存每隔一段时间会耗尽 [问题分析] 由于使用的是go语言开发的,所以采用了业界流行的工具pprof. ...
随机推荐
- VirtualBox中的虚拟机在Ubuntu 下无法启动之问题解决
我通过重新安装box解决的.发现,box安装,直接apt install有可能会出现虚拟机无法启动的问题. 一.添加VirtualBox的源并安装5.1版本virtualbox官网:https://w ...
- 安装Python3后,centos使用yum报错
题记 在之前的文章中我自定义安装了Python3,并且修改了默认的 Python软链,今天想搭建一个 ftp 服务器,使用命令的时候出现了一个错误: 问题 1.使用 yum 安装 ftp工具 yum ...
- ios 工具大全,最全框架
https://www.jianshu.com/p/e280f3348156 [链接]文件分享 - 网盘分享https://share.weiyun.com/5A1aura
- Broadcast总结 service
有时候离开应用就会接收不到系统的广播是因为系统默认发送的广播都会有一个参数 ntent startIntent = new Intent();startIntent.putExtra("pk ...
- struts框架问题六之从值栈中获取值
6. 问题六: 在JSP中获取值栈的数据 * 总结几个小问题: > 访问root中数据 不需要# > 访问context其它对象数据 加 # > 如果向root中存入对象的话,优先使 ...
- Thread(线程)和ThreadPool(线程池) Thread回调与返回值
Thread(线程) Thread开启线程:接收一个参数 TestClass tc = new TestClass(); //没有返回值,有一个object类型的参数的委托:两种写法. Paramet ...
- win7系统administrator用户提示没有管理员权限,造装驱动安装错误,软件无法使用
警告1909.无法创建快捷方式 最近使用windows 7 32位安装软件,好多都失败.出现以上类似错误. 解决方法:在系统盘(C:)右键属性“安全”选项卡--“编辑”,添加“Everyone”设置为 ...
- maven 发布打包部署 命令
一.配置好jdk 二.下载安装maven http://maven.apache.org/download.cgi 三.添加环境变量 1. 添加 M2_HOME 和 MAVEN_HOME 环境变量到 ...
- Linux indent命令
一.简介 indent可辨识C的原始代码文件,并加以格式化,以方便程序设计师阅读. 二.选项 http://www.cnblogs.com/xuxm2007/archive/2011/11/03/22 ...
- mysql 执行多线程临时方案
sqr::IDatabase *db=NULL;IDbConnection *conn = NULL;int main(int argc, char* argv[]) { db = GetDataba ...