美文网首页
C++解Netty网络数据包

C++解Netty网络数据包

作者: 何亮hook_8285 | 来源:发表于2022-10-07 13:45 被阅读0次

Netty网络框架对protobuf进行封装,在网络传输过程为了解决数据粘包问题,提供了以下编码器和解码器。

ProtobufVarint32FrameDecoder  数据解码器
ProtobufVarint32LengthFieldPrepender 数据编码器

ProtobufVarint32LengthFieldPrepender 将数据编码成以下格式

   原始数据                          编码数据
 * BEFORE ENCODE (300 bytes)       AFTER ENCODE (302 bytes)
 * +---------------+               +--------+---------------+
 * | Protobuf Data |-------------->| Length | Protobuf Data |
 * |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |
 * +---------------+               +--------+---------------+

ProtobufVarint32LengthFieldPrepender将数据解码成以下格式

 原始数据                           解码数据
 * BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)
 * +--------+---------------+      +---------------+
 * | Length | Protobuf Data |----->| Protobuf Data |
 * | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |
 * +--------+---------------+      +---------------+

以上数据格式中使用length来记录数据的长度,这里length用的不是传统int类型存储长度,而是使用的Varint32类型存储数据长度。

Varint32类型是可变宽度整数,它允许使用 1 到 10 个字节对无符号 64 位整数进行编码,可实现较小的数值使用更少的字节。

那C++如何使用Varint32类型的数据,可参考以下代码

#include <google/protobuf/io/coded_stream.h>
using namespace google::protobuf::io;

//将Varint32转int类型
inline const uint8_t* ReadVarint32FromArray(const uint8_t* buffer, uint32_t * value) {
    static const int kMaxVarintBytes = 10;
    static const int kMaxVarint32Bytes = 5;

    // 快速路径:缓冲区中还有足够的字节可保证
    //这个读数不会超过末尾,所以我们可以跳过检查。
    const uint8_t* ptr = buffer;
    uint32_t b;
    uint32_t result;

    b = *(ptr++); result  = (b & 0x7F)      ; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) <<  7; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |=  b         << 28; if (!(b & 0x80)) goto done;

    // 如果输入大于32位,我们仍然需要全部读取
    // 并丢弃高位。
    for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
        b = *(ptr++); if (!(b & 0x80)) goto done;
    }

    // 我们超出了变量的最大大小(10字节)。假定数据已损坏
    return NULL;

    done:
    *value = result;
    return ptr;
}

//获取int类型转varint占多少字节
static int computeRawVarint32Size(int value) {
    if ((value & (0xffffffff <<  7)) == 0) {
        return 1;
    }
    if ((value & (0xffffffff << 14)) == 0) {
        return 2;
    }
    if ((value & (0xffffffff << 21)) == 0) {
        return 3;
    }
    if ((value & (0xffffffff << 28)) == 0) {
        return 4;
    }
    return 5;
}


int main() {
    //定义数据长度
    uint32_t testNum=3593904516;
    //Varint32占用字节长度
    int placeSize=computeRawVarint32Size(testNum);
    //存储Varint32的字节数组变量
    uint8_t *buffer=new uint8_t[placeSize];
    //将int变量转Varint32变量
    CodedOutputStream::WriteVarint32ToArray(testNum,buffer);
    
    //将Varint32转int变量
    uint32_t result;
    ReadVarint32FromArray(buffer,&result);
    std::cout << result <<std::endl;
    return 0;
}

c++使用socket发送数据到netty

WSADATA wsa;
WSAStartup(MAKEWORD(2,2),&wsa);
//初始化socket
int fd=socket(AF_INET,SOCK_STREAM,0);
sockaddr_in sockaddrIn;
sockaddrIn.sin_port=htons(9988);
sockaddrIn.sin_family=AF_INET;
evutil_inet_pton(sockaddrIn.sin_family, "127.0.0.1", (void *)&sockaddrIn.sin_addr);
int sockleng=sizeof(sockaddrIn);
//连接netty服务器
connect(fd,(sockaddr*)&sockaddrIn,sockleng);

//初始化protobuf对象
Person *p1=new Person;
p1->set_age(121212);
p1->set_sex(MAN);
p1->set_image("asdasd");
p1->set_brithday("2020-01-1");
p1->set_name("zhangsan");
p1->set_status(true);
p1->set_picture("1.png");
Address *ad=p1->add_myaddress();
ad->set_citycode("430321");
ad->set_desc("xiangtanshi");

//读取图片
ifstream fin("D:\\1.png",std::ios::binary);
int imageSize=fin.seekg(0,std::ios::end).tellg();
std::vector<char> imageBuffer(imageSize);
fin.seekg(0,std::ios::beg).read(&imageBuffer[0],static_cast<std::streamsize>(imageBuffer.size()));
fin.close();

string image_data;
image_data.assign(imageBuffer.data(),imageSize);
//绑定图片
p1->set_image(image_data);
//获取person对象二进制长度
int size=p1->ByteSizeLong();
//计算int类型转Varint32占多少字节
int len=computeRawVarint32Size(size);
char *data=new char[size+len];
//int类型转Varint32
uint8_t  *test=CodedOutputStream::WriteVarint32ToArray(size,(uint8_t*)data);
std::cout << *test << std::endl;
//将对象序列化字节
p1->SerializeToArray(data+len,size);

std::cout << "size=" << size << std::endl;
//发送数据到服务端
send(fd,data,size+ len,0);
//关闭连接
closesocket(fd);

相关文章

  • C++解Netty网络数据包

    Netty网络框架对protobuf进行封装,在网络传输过程为了解决数据粘包问题,提供了以下编码器和解码器。 Pr...

  • Netty入门

    Netty是一个异步的事件驱动网络框架,使用Netty可以研发高性能的私有协议,将业务逻辑和网络进行解耦,通过Ne...

  • 协议调用时长监控

    罪恶潜伏在各个角落。 --VN 游戏中的业务逻辑,通常是不建议在网络数据包接收线程池中处理的(如Netty Wor...

  • 网络编程-关闭连接(2)-Java的NIO在关闭socket时,

    背景 在上一讲网络编程-关闭连接-C/C++相关系统调用中,提到过,目前项目使用Netty框架来实现的网络编程,查...

  • Netty学习--传输

    传输迁移 未使用Netty 的阻塞网络编程 未使用Netty 的异步网络编程 使用Netty 的阻塞网络处理 使用...

  • 传统IO,NIO,netty的几种实现方式

    1.未使用 Netty 的阻塞网络编程 2.未使用 Netty 的异步网络编程 3.使用 Netty 的阻塞网络处...

  • 网络协议 Day07 网络层 UDP

    一、网络层 1. 网络层数据包总的包括哪两块? 网络层数据包(IP 数据包,Packet)由首部、数据 2 部分组...

  • Java NIO

    书本 Netty权威指南netty实战O’Reilly的《Java nio》Unix网络编程 《unix网络编程》...

  • 网络协议分层

    1- 通过wireshark 分析网络数据包 1.1 以太网数据包 1.2 IP 数据包 1.3 TCP 数据包 ...

  • java-netty

    netty常用API学习 netty简介 Netty是基于Java NIO的网络应用框架. Netty是一个NIO...

网友评论

      本文标题:C++解Netty网络数据包

      本文链接:https://www.haomeiwen.com/subject/etlbartx.html