Golang的socket编程(四):解决粘包问题及制定通信协议

马谦马谦马谦 Golang评论4021字数 1300阅读4分20秒阅读模式

一、概述

前面已经完成了一个完美的多并发CS模型,但美中不足的是没有解决粘包问题。

1.1 什么是粘包问题?

在网络传输中,数据都是通过数据流来传输的,也就是以比特来传输。传输的过程中我们可能会遇到各种各样的问题导致数据传输异常,最常见的就是网络发送时延。网络时延会导致服务端此时收到的数据的时间有偏差,然后就导致数据接收数据的时间不一致。

可以看一个例子,修改上篇的服务端和客户端为以下内容:

客户端改为以下:

以上我们发送了100条json到服务端,按照预想服务端将会输出100行json,但是实际上并不是:

Golang的socket编程(四):解决粘包问题及制定通信协议-图片1

这个现象产生的原因是因为服务端每次读取数据之后将会休眠1ns,但是对于客户端来说,这1ns它还在一直传输数据,1ns的时间可能 发送了1条,也可能是2条,这个数量我们不知道是多少,也无法控制。于是就导致数据堆积,服务端再读取就会出问题了。与此同时,由于缓冲区有限,一次最多读取2048个字节,堆积的字节超过2048的也无法读取,只能留到下次读取,这种现象就是粘包问题。

二、解决办法

上面抛出了粘包的问题后,现在就要开始想办法处理了,怎么处理呢?这里就需要用到协议了,协议就是双方约定好的数据包格式, 让服务端知道从哪里开始读,读到哪里结束,这样就不会出错了。实现这个协议最简单的办法就是加上一个协议头和一个数据包长度 。

假设现在要发送[0x11, 0x22, 0x33],约定协议头为[0xaa, 0xbb],由于发送数据的长度是三个字节,所以经过客户端封装之后的数据就变成了[0xaa, 0xbb, 0x03, 0x11, 0x22, 0x33]

服务端收到数据后,先找[0xaa, 0xbb]的位置,然后根据他们的位置得到数据长度为3,于是再往后读三个字节就是真正的的数据 部分了。

三、实现

指定好了协议之后就可以开始实现了,为了方便,直接把这里写成一个对象:

包头的定义:

包头包括协议头和数据长度,共六个字节。

3.1 数据发送时的封装

writeByte()的实现

3.2 接收数据时解包

readHead()的实现:

readNByte()的实现:

3.3 完整代码

四、服务端

五、客户端

六、运行

运行服务端再运行客户端就会发现,已经不和之前的一样了,整整齐齐,perfect!

Golang的socket编程(四):解决粘包问题及制定通信协议-图片2

 

 最后更新:2017-11-18
马谦马谦马谦
  • 本文由 马谦马谦马谦 发表于 2017年9月13日22:19:46
  • 转载请务必保留本文链接:https://www.dyxmq.cn/program/code/golang/golang-socket-4.html
解决gvm工具无法下载安装包的问题 Golang

解决gvm工具无法下载安装包的问题

GVM(Go Version Manager)是一款用于管理和切换不同Go语言版本的工具。它允许用户在同一台计算机上轻松安装、使用和管理多个Go版本,同时还能确保项目之间的依赖关系井然有序。GVM的主...
国内几个优质的Go Module代理仓库服务 Golang

国内几个优质的Go Module代理仓库服务

一、简介 go module公共代理仓库,代理并缓存go模块。你可以利用该代理来避免DNS污染导致的模块拉取缓慢或失败的问题,加速你的构建。 简单来说就是国内访问被墙,go get无法在线获取到仓库,...
socket多路IO复用之select模型 C/C++

socket多路IO复用之select模型

select模型是socket中的一种多路IO复用模型之一,通过轮询的方式来完成多路访问控制。 一个很简单的例子来描述select模型: 幼儿园老师要照顾所有的小朋友,每天他都会轮流去问小朋友:“小朋...
TCP协议中的三次握手和四次挥手 TCP/IP

TCP协议中的三次握手和四次挥手

一、三次握手 TCP协议的三次握手和四次挥手分别表示了TCP连接的建立和释放过程,在整个TCP协议是一个很重要的内容,同时也是面试时的常见考点。 趁着找工作的劲,使用socket+tcpdump分析了...
匿名

发表评论

匿名网友
:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:
确定

拖动滑块以完成验证