Буферы протокола Google не работают с UDP? - PullRequest
4 голосов
/ 05 декабря 2011

Я знаю, что это может быть глупо, но мой пакет сообщений, определенный с помощью буферов протокола 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;
}

Для проблемы, о которой упоминал Джон, я тоже пробовал, все равно не работает.

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

1 Ответ

11 голосов
/ 05 декабря 2011

Я подозреваю, что это проблема:

strcpy(Sentence, array);

Вы используете strcpy - это остановится, как только оно достигнет 0 байтов, потому что обрабатывает эти несколько произвольные двоичные данные как строку. Я подозреваю, что вы должны использовать memcpy вместо.

Кроме того, не используйте strlen позже. Избегайте всех функций, которые обрабатывают данные как текст.

(В общем, я бы с осторожностью использовал буферы протокола с UDP, если у вас нет веских оснований полагать, что каждое сообщение поместится в один пакет, но это отдельный вопрос.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...