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

时间:2011-12-05 06:13:40

标签: c++ udp protocol-buffers

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

我的原型文件如下:

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 <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#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 <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#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));

1 个答案:

答案 0 :(得分:11)

我怀疑这是问题所在:

strcpy(Sentence, array);

你正在使用strcpy - 它会在遇到0字节时立即停止,因为它将这个有点任意的二进制数据视为字符串。我怀疑你应该使用memcpy代替。

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

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