由于PROTOBUF服务器中的字符串数据类型变量和客户端通过cpp中recv端的套接字进行通信,因此正在获取segfau

Getting segfault due to string data type variable in PROTOBUF server and client communication through sockets on recv end in cpp

本文关键字:通信 套接字 segfau 获取 cpp 数据 字符串 服务器 PROTOBUF 类型变量 由于      更新时间:2023-10-16

当我通过recv端的套接字通信发送protobuf变量时,我正试图显示protobuf的字符串变量。我在除字符串之外的其余数据类型中进行了分段。它们工作正常,但字符串变量情况下我进行了分段如何在protobuf中进行除任何其他数据类型之外的字符串数据类型分段错误存储字符串数据类型。

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

如何解决此问题

示例.proto

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

服务器.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 FAILn";
    else
        cout<<"Bind Successn";
    if((csd=accept(sd,(struct sockaddr *)&cli, &s))==-1)
        cout<<"Connection Accept FAILn";
    else
        cout<<"ConnectioN Accept Successn";
    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 FAILn";
    else
        cout<<"connect Successn";
    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-wire格式反序列化/序列化,则无法直接接收/发送该实例。看看protobuf::MessageLite类的ParseFrom SerializeTo方法。

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

更新:
试试这样的s.th:

发件人.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 

接收器.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.

注意:
从/到与各种语言绑定一起使用的唯一、高效的有线格式的反序列化是google协议缓冲区的全部意义。

对于处理可能的发送方/接收方模式,您可能会发现0MQ是一个有用的框架,而不是创建"原始"套接字。无论如何,请听好的建议(!):保持消息(有效负载)格式和发送/recv行为尽可能分开。