zl程序教程

您现在的位置是:首页 >  云平台

当前栏目

关于 protobuf 在网络传输中数据丢失问题解决方案

网络数据解决方案 关于 传输 丢失 Protobuf 问题
2023-09-14 09:09:11 时间

如上。

排查过程:

syntax = "proto3";

message login_request{
    fixed32 id = 1;
    fixed32 pwd = 2;
}

message login_reply{
    fixed32 errno_id = 1;
    fixed32 money = 2;
}
#include <stdio.h>
#include "msg.pb.h"
#include <string>
using namespace std;

int main()
{
    login_request lrs,reply;
    lrs.set_id(12345678);
    lrs.set_pwd(12345678);
    string str = lrs.SerializeAsString();
   
    reply.ParseFromString(str);
    printf("id:%d\n",reply.id());
    printf("pwd:%d\n",reply.pwd());
    return 0;
}

确定问题不是出在protobuf这边之后,那就只能是网络传输过程或者传输前后的字符串转化过程中出现问题了。


#include <stdio.h>
#include "msg.pb.h"
#include <string>
using namespace std;

int main()
{
    login_request lrs,reply;
    lrs.set_id(12345678);
    lrs.set_pwd(12345678);
    string str = lrs.SerializeAsString();
    const char *c = str.c_str();
    
    string str2 = c;
    reply.ParseFromString(str2);
    printf("id:%d\n",reply.id());
    printf("pwd:%d\n",reply.pwd());
    return 0;
}

这时候pwd已经为0了,数据发生了丢失。但是id依旧正常。


猜测是长度问题,因为早上解决另一个问题的时候再Stack Overflow上有人说要带上包长度。


于是:

#include <stdio.h>
#include "msg.pb.h"
#include <string>
using namespace std;

int main()
{
    login_request lrs,reply;
    lrs.set_id(12345678);
    lrs.set_pwd(12345678);
    string str = lrs.SerializeAsString();
    const char *c = str.c_str();
    
    string str2;
    str2.assign(c,str.length());
    reply.ParseFromString(str2);
    printf("id:%d\n",reply.id());
    printf("pwd:%d\n",reply.pwd());
    return 0;
}

至此实验结束,让我们再看看为什么会这样.


#include <stdio.h>
#include "msg.pb.h"
#include <string>
using namespace std;

int main()
{
    login_request lrs,reply;
    lrs.set_id(12345678);
    lrs.set_pwd(12345678);
    string str = lrs.SerializeAsString();
    const char *c = str.c_str();
    
    string str2;
    string str3 = c;
    str2.assign(c,str.length());
    reply.ParseFromString(str2);
    printf("id:%d\n",reply.id());
    printf("pwd:%d\n",reply.pwd());
    printf("str.length():%d\n",str.length());
    printf("str2.length():%d\n",str2.length());
    printf("str3.length():%d\n",str3.length());
    printf("c.length():%d\n",strlen(c));	//4
    return 0;
}

结果可自行验证。当你决定使用 const char* 的时候,你就已经放弃了长度信息。


一定要用const char *吗?

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

不然这个函数为什么要我们输入一个 len?好玩吗?

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

至此,问题解决。