使用Go语言为服务器,QT作为客户端,利用TCP进行数据传输,当两次发送间隔过近会产生粘包现象,此时就需要一个特定的数据格式用来区分两个数据的边界,我使用 特征码(int类型用来区分是否恶意)数据包大小(int)压缩标志(bool)数据(byte),但当交互时发生问题,比如QT的自定义数据格式QBytearry会在最前面加个字段用来表示自身整体大小。下面直接列出代码:
GO:
func IntToBytes(n int) []byte { tmp := int32(n) bytesBuffer := bytes.NewBuffer([]byte{}) binary.Write(bytesBuffer, binary.BigEndian, tmp) return bytesBuffer.Bytes() } func booltobyte(n bool) []byte { bytesBuffer := bytes.NewBuffer([]byte{}) binary.Write(bytesBuffer, binary.BigEndian, n) return bytesBuffer.Bytes() }
上面两个函数用于转换,将int bool 转成byte数组
其实自己写位运算也可以实现
var buffer bytes.Buffer size := IntToBytes(int(9) + len(k)) feature := IntToBytes(int(15)) iscompress := booltobyte(false) data := []byte(k) buffer.Write(size) buffer.Write(feature) buffer.Write(iscompress) buffer.Write(data) conn.Write(buffer.Bytes())
先获取总体大小int 为4字节 bool为1字节因此首先就是4*2+1=9个字节,然后再加上数据大小最后就变为9+len(k)
再将size feature iscompress data 发送出去即可
QT c++:
int bytetoint(QByteArray data){ int j = data[3] & 0x000000ff; j |= ((data[2] << 8) & 0x0000ff00); j |= ((data[1] << 16) & 0x00ff0000); j |= ((data[0] << 24) & 0xff000000); return j; } bool bytetobool(QByteArray data){ bool k = data[0]&0x00000001; return k; }
if(receive_data.size()>(sizeof(int)+sizeof(int))) { bool isCompress; int data_size; int feature; QByteArray data; std::string k= receive_data.toStdString(); qDebug()<<QString::fromStdString(k)<<k.size(); data=receive_data.mid(0,4); data_size=bytetoint(data); receive_data.remove(0,4); data=receive_data.mid(0,4); feature=bytetoint(data); receive_data.remove(0,4); data=receive_data.mid(0,1); isCompress=bytetobool(data); receive_data.remove(0,1); qDebug()<<isCompress<<data_size<<feature; data=receive_data.mid(0,data_size-9); qDebug()<<QString(data); receive_data.clear(); process_data(data); receive_data.remove(0,data_size); }
接收数据后先看看够不够前面两个数据,读取特征值与总数据包大小,看看数据包总体大小够不够,然后对其进行解析。