记一次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. ...
随机推荐
- 正向工程configuration配置连接
在执行正向工程的时候需要用到这个关键词里面的configure();方法, 这个方法有好几个重构, 都是参数不一样的, 也可以空着不写, 不写的话就会默认去找hibernate.cfg.xml这个文件 ...
- css3文字截断
width:200px; height:14px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; text-overflow ...
- 二级联动的作业&左右移动作业
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- MongoDB的数据类型(四)
JSON JSON是一种简单的数据表示方式,它易于理解.易于解析.易于记忆.但从另一方面来说,因为只有null.布尔.数字.字符串.数组和对象这几种数据类型,所以JSON有一定局限性.例如,JSON没 ...
- .Net多线程 并行编程(三)---并行集合
为了让共享的数组,集合能够被多线程更新,我们现在(.net4.0之后)可以使用并发集合来实现这个功能. 而System.Collections和System.Collections.Generic命名 ...
- css简单分页
html代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...
- PAT 1073 多选题常见计分法(20)(代码+思路)
1073 多选题常见计分法(20 分) 批改多选题是比较麻烦的事情,有很多不同的计分方法.有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数:如果考生 ...
- [SoapUI] 重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息
重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息 package d ...
- [Fiddler] 开启Fiddler抓包的时候产品报“证书错误”
报错截图: 解决办法:同时开启产品和Fiddler,做如下处理:
- Maven系列(一)plugin
Maven系列(一)plugin maven-compiler-plugin 使用 mvn compile 命令,出现错误: 编码 GBK 的不可映射字符而不能编译.这是因为代码或注释中存在中文引起的 ...