由于PROTOBUF服务器中的字符串数据类型变量而导致段错误,并且通过cpp中的recv端口上的套接字进行客户端通信

时间:2022-08-26 19:49:42

When I am sending a protobuf variable through socket communication on recv end I am trying to display the string variable of protobuf I got segmentation in this remaining Data type other than String they are working fine but string variable case I got segmentation How can I over come in Protobuf string datatype segmentation fault other than we have any other data type for store the string data type.

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

I create a example.proto with in string variable name is there I am compile example.proto with protoc compiler (protoc example.proto --cpp_out <path>) it create two files two files example.pb.h, example.pb.cc By using these files I create a test_server.cpp and test_client.cpp And compile it. but at the time of both programms runing I sent a protobuf variable on recv side it give segmentation fault due to trying to display string variable.

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

How can I solve this problem?

我怎么解决这个问题?

example.proto

example.proto

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

server.cpp

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);
}

client.cpp

client.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);
}

1 个解决方案

#1


1  

Your problem is here:

你的问题在这里:

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

and here:

和这里:

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

You can't receive/send the star instance directly without de/serializing it from/to protobuf wire format first. Have a look at the ParseFrom SerializeTo methods of the protobuf::MessageLite class.

您不能直接接收/发送星型实例,而无需首先从/向protobuf有线格式将其/序列化。看看protobuf :: MessageLite类的ParseFrom SerializeTo方法。

The best way is to send the length of the serialized message first in a fixed format (e.g. a uint32_t in network byte order). Then the receiver can read this first and allocate a buffer of the appropriate size before receiving the serialized message that is send afterwards.

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

UPDATE:
Try s.th. like this:

更新:尝试s.th.喜欢这个:

Sender.cpp

Sender.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

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.

NOTE:
De-/Serializing from/to a unique, efficient wire format used with various language bindings is the whole point of google protocol buffers.

注意:从/向各种语言绑定使用的独特,高效的有线格式进行序列化是Google协议缓冲区的重点。

For twiddling out the bits of possible sender/receiver patterns, instead of creating 'raw' sockets you might find 0MQ being a useful framework. Anyway listen to good advice(!): Keep message (payload) format and send/recv behavior as separate as possible.

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

#1


1  

Your problem is here:

你的问题在这里:

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

and here:

和这里:

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

You can't receive/send the star instance directly without de/serializing it from/to protobuf wire format first. Have a look at the ParseFrom SerializeTo methods of the protobuf::MessageLite class.

您不能直接接收/发送星型实例,而无需首先从/向protobuf有线格式将其/序列化。看看protobuf :: MessageLite类的ParseFrom SerializeTo方法。

The best way is to send the length of the serialized message first in a fixed format (e.g. a uint32_t in network byte order). Then the receiver can read this first and allocate a buffer of the appropriate size before receiving the serialized message that is send afterwards.

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

UPDATE:
Try s.th. like this:

更新:尝试s.th.喜欢这个:

Sender.cpp

Sender.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

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.

NOTE:
De-/Serializing from/to a unique, efficient wire format used with various language bindings is the whole point of google protocol buffers.

注意:从/向各种语言绑定使用的独特,高效的有线格式进行序列化是Google协议缓冲区的重点。

For twiddling out the bits of possible sender/receiver patterns, instead of creating 'raw' sockets you might find 0MQ being a useful framework. Anyway listen to good advice(!): Keep message (payload) format and send/recv behavior as separate as possible.

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