c++ - 由于 PROTOBUF 服务器中的字符串数据类型变量和客户端通过 cpp 中 recv 端的套接字进行通信而导致段错误

标签 c++ linux sockets protocol-buffers

当我在 recv 端通过套接字通信发送 protobuf 变量时,我试图显示 protobuf 的字符串变量,我在除 String 之外的剩余数据类型中得到了分段,它们工作正常,但字符串变量的情况下,我得到了分段怎么能除了我们有任何其他数据类型来存储字符串数据类型之外,我还遇到了 Protobuf 字符串数据类型段错误。

我用字符串变量名创建了一个 example.proto 我正在使用 protoc 编译器编译 example.proto ( protoc example.proto --cpp_out <path> ) 它创建两个文件两个文件 example.pb.h, example.pb.cc 通过使用这些文件,我创建了一个 test_server.cpp 和 test_client.cpp 并编译它。但是在两个程序运行时,我在 recv 端发送了一个 protobuf 变量,由于试图显示字符串变量,它给出了段错误。

我该如何解决这个问题?

example.proto

package data;
message  star
{ optional string name=1; }

server.cpp

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<strings.h>
#include<string.h>
#include <arpa/inet.h>
#include"example.pb.h"
#include"example.pb.cc"

int main() 
{ 
    int sd,csd;
    sd=socket(AF_INET, SOCK_STREAM,0);
    perror("socket");
    sockaddr_in ser,cli;
    ser.sin_family=AF_INET;
    ser.sin_port=htons(7878);
    ser.sin_addr.s_addr=inet_addr("X.Y.Z.A");
    bzero(ser.sin_zero, 8);
    size_t s=16;

    if(bind(sd,(struct sockaddr *)&ser, s)==-1)
        cout<<"Bind FAIL\n";
    else
        cout<<"Bind Success\n";

    if((csd=accept(sd,(struct sockaddr *)&cli, &s))==-1)
        cout<<"Connection Accept FAIL\n";
    else
        cout<<"ConnectioN Accept Success\n";

    star pkt;
    recv(csd,&pkt,sizeof(pkt),0);
    cout<<"\t String Name: "<<pkt.name<<endl; //Here only i get segmentation
    close(sd);
    close(csd);
}

客户端.cpp

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<strings.h>
#include<string.h>
#include <arpa/inet.h>
#include"example.pb.h"
#include"example.pb.cc"

int main()
{
    int sd;
    sd=socket(AF_INET, SOCK_STREAM,0);
    perror("socket");
    sockaddr_in ser;
    ser.sin_family=AF_INET;
    ser.sin_port=htons(7878);
    ser.sin_addr.s_addr=inet_addr("X.Y.Z.A");
    bzero(ser.sin_zero, 8);

    if(connect(sd,(struct sockaddr *)&ser, 16)==-1)
        cout<<"connect FAIL\n";
    else
        cout<<"connect Success\n";

    star pkt;
    pkt.set_name("Pratap");
    cout<<"Send Data without help of another variable....\n";
    send(sd,&pkt,sizeof(pkt) ,MSG_CONFIRM);
    close(sd);
}

最佳答案

你的问题在这里:

star pkt;
recv(csd,&pkt,sizeof(pkt),0);

这里:

star pkt;
pkt.set_name("Pratap");
cout<<"Send Data without help of another variable....\n";
send(sd,&pkt,sizeof(pkt) ,MSG_CONFIRM);

您不能直接接收/发送 star 实例,而无需先将其从 protobuf 有线格式反序列化/序列化。查看 protobuf::MessageLiteParseFrom SerializeTo 方法类。

最好的方法是先以固定格式发送序列化消息的长度(例如网络字节顺序的uint32_t)。然后接收方可以先读取它并分配一个适当大小的缓冲区,然后再接收随后发送的序列化消息。

更新:
试试……像这样:

发件人.cpp

star pbMsgObj;
pbMsgObj.set_name("Pratap");

std::string pkt;
pbMsgObj.SerializeToString(&pkt); // Serialize the message object to 
                                  // protobuf wire format.
uint32_t msgLength = pkt.size();
uint32_t sndMsgLength = htonl(msg_length); // Ensure network byte order

send(sd,&sndMsgLength ,sizeof(uint32_t) ,MSG_CONFIRM); // Send the message length
send(sd,pkt.c_str() ,msgLength ,MSG_CONFIRM); // Send the message data 

Receiver.cpp

star msgObject;
uint32_t msgLength;
recv(csd,&msgLength,sizeof(uint32_t),0); // Receive the message length
msgLength = ntohl(msgLength); // Ensure host system byte order

std::vector<uint8_t> pkt; // Allocate a receive buffer
pkt.resize(msgLength,0x00);

recv(csd,&(pkt[0]),msgLength,0); // Receive the message data
std::string tmp;
tmp.assign(&(pkt[0]),pkt.size()); // Convert message data to a string

msgObject.ParseFromString(tmp); // Deserialize the message object from
                                // protobuf wire format.

注意:
对与各种语言绑定(bind)一起使用的独特、高效的有线格式进行反序列化/反序列化是 google protocol buffers 的重点。

为了找出可能的发送方/接收方模式的位,而不是创建“原始”套接字,您可能会发现 0MQ是一个有用的框架。无论如何,请听取好的建议(!):尽可能将消息(有效负载)格式和发送/接收行为分开。

关于c++ - 由于 PROTOBUF 服务器中的字符串数据类型变量和客户端通过 cpp 中 recv 端的套接字进行通信而导致段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18463414/

相关文章:

python - Golang net.Listen 绑定(bind)到已在使用的端口

c++ - 在 Windows 中分配内存

linux - 一个用户而不是另一个用户的Python模块导入错误

c++ - 在大型 C/C++ 项目的编译时使用 GNU m4

linux - Node.js + peerjs 不使用 ssl

Java HTTPS 代理/重定向服务器

sockets - 一端的套接字上的 close() 是否也会在另一端关闭?

c++ - 在 C++ 中初始化指针是强制性的吗?

c++ - 默认构造函数为空时做什么?

c++ - 有没有办法在 Mac OS 上播放系统提示音?