当前位置:  开发笔记 > 编程语言 > 正文

Google协议缓冲区不适用于UDP?

如何解决《Google协议缓冲区不适用于UDP?》经验,为你挑选了1个好方法。

我知道这可能很愚蠢,但我使用Google协议缓冲区定义的消息包并不能很好地与UDP一起使用UDP.当我通过UDP从客户端到服务器从序列化包(我只有一些普通字段)发送常规字符串时,每件事情都很好.但是当我添加一个重复的字段时,序列化的字符串只能被接收到整体的一部分.第一个字段将被完全接收,但所有其余字段将丢失.代码用c ++,Google协议缓冲区2.3.0,Linux编写.欢迎任何帮助.谢谢.

我的proto文件如下:

message Package{
    optional string virtualPath = 1;
    optional int32 num = 2;//0=insert, 1=find, 2=remove.
    optional string realFullPath = 3;
    optional bool isDir = 4;
    repeated string listItem = 5;
    optional int32 openMode = 6;
    optional int32 mode = 7;
    optional int32 Operation = 8;       
    optional int32 replicaNo =9; 
}

服务器端:

#include 
#include 
#include 
#include 
#include 
#include "zht_util.h"
int main(int argc, char *argv[]) {
    struct sockaddr_in sad; 
    int port = 50000; 
    struct sockaddr_in cad; 
    int alen; 
    int serverSocket; 
    char clientSentence[1000];
    char capitalizedSentence[1000];
    char buff[1000];
    int i, n;
    serverSocket = socket(PF_INET, SOCK_DGRAM, 0); /* CREATE SOCKET */
    if (serverSocket < 0) {
        fprintf(stderr, "socket creation failed\n");
        exit(1);
    }

    memset((char *) &sad, 0, sizeof(sad)); 
    sad.sin_family = AF_INET; 
    sad.sin_addr.s_addr = INADDR_ANY; 
    sad.sin_port = htons((u_short) port);

    if (bind(serverSocket, (struct sockaddr *) &sad, sizeof(sad)) < 0) {
        fprintf(stderr, "bind failed\n");
        exit(1);
    }

    while (1) {
        clientSentence[0] = '\0';
        alen = sizeof(struct sockaddr);
        socklen_t len = (socklen_t) alen;
        n = recvfrom(serverSocket, buff, sizeof(buff), 0,
                (struct sockaddr *) &cad, &len);
        strncat(clientSentence, buff, n);
        printf("Server received :%s \n", clientSentence);
    }
    return 0;
}

客户端:

#include 
#include 
#include 
#include 
#include 
#include "zht_util.h"
int main(int argc, char    *argv[])

{ 
  struct  sockaddr_in sad; 
  int     clientSocket;     
  struct  hostent  *ptrh;  

  char    *host;           
  int     port;            

  char    Sentence[1000];
  char    modifiedSentence[1000];
  char    buff[1000];
  int     n;

  host = "localhost";
  port = 50000;

 clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
  if (clientSocket < 0) {
    fprintf(stderr, "socket creation failed\n");
    exit(1);
  }

   memset((char *)&sad,0,sizeof(sad)); 
  sad.sin_family = AF_INET;           
  sad.sin_port = htons((u_short)port);
  ptrh = gethostbyname(host); 
  if ( ((char *)ptrh) == NULL ) {
    fprintf(stderr,"invalid host: %s\n", host);
    exit(1);
  }
  memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);


  HostEntity destination;
    destination.host = "localhost";
    destination.port = 50000;
    int current_sock = -1;

    Package package;
    package.set_virtualpath(randomString(25)); 
    package.add_listitem("item--1");
    package.add_listitem("item--2");
    package.add_listitem("item--3");
    package.add_listitem("item--4");
    package.add_listitem("item--5");
    package.set_realfullpath("Some-Real-longer-longer-and-longer-Paths");
    cout << "package size: " << package.ByteSize() << endl;
    char array[package.ByteSize()];
    package.SerializeToArray(array, package.ByteSize());
    strcpy(Sentence, array);

  n=sendto(clientSocket, Sentence, strlen(Sentence)+1,0 ,
       (struct sockaddr *) &sad, sizeof(struct sockaddr));

  printf(" Client sent %d bytes to the server\n", n);


  close(clientSocket);
  return 0;
}

对于Jon提到的问题,我也试过这个,但仍然无效.

string Sentence = package.SerializeAsString();
n=sendto(clientSocket, Sentence.c_str(), (Sentence.size())+1,0 ,(struct sockaddr *) &sad, sizeof(struct sockaddr));

Jon Skeet.. 11

我怀疑这是问题所在:

strcpy(Sentence, array);

你正在使用strcpy- 一旦它到达0字节就会停止,因为它将这个有点任意的二进制数据视为一个字符串.我怀疑你应该使用memcpy.

同样,以后不要使用strlen.避免将数据视为文本的所有函数.

(一般情况下,我要小心使用带有UDP的协议缓冲区,除非你有充分的理由相信每条消息都适合单个数据包,但这是另一回事.)



1> Jon Skeet..:

我怀疑这是问题所在:

strcpy(Sentence, array);

你正在使用strcpy- 一旦它到达0字节就会停止,因为它将这个有点任意的二进制数据视为一个字符串.我怀疑你应该使用memcpy.

同样,以后不要使用strlen.避免将数据视为文本的所有函数.

(一般情况下,我要小心使用带有UDP的协议缓冲区,除非你有充分的理由相信每条消息都适合单个数据包,但这是另一回事.)


@Tony:嗯,基本上你应该将你的问题分成两部分:序列化/反序列化协议缓冲区,传输数据包而不会丢失任何东西(包括长度).您应该能够在不使用套接字*或*的情况下重现问题*,而不使用协议缓冲区.毕竟,数据包只是不透明的数据位 - 它不像UDP理解它们是协议缓冲区消息.(无论这是否是*唯一*问题,它肯定是*问题.)
推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有