2011-12-05 124 views
4

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

我的原文件如下:

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)); 
+2

为什么不你使用TCP?什么是使用UDP的原因? (无论如何,大部分时间都用于传输,所以你应该使用TCP)。 –

+2

你确定你的邮件完全符合128字节吗? – sarnold

+2

有很多有效的理由使用UDP;例如,如果您正在流式传输实时视频或音频,并且不希望传输延迟并在每次数据包丢失时重新传输无用的过时数据,或者如果您要发送多播或广播数据,哪些TCP不支持。 –

回答

11

我怀疑这就是问题所在:

strcpy(Sentence, array); 

您使用strcpy - 这是怎么回事,因为它击中一个0字节尽快停止,因为它处理这个有点任意的二进制数据作为串。我怀疑你应该使用memcpy

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

(一般来说,我会谨慎使用Protocol Buffers与UDP,除非你有充分的理由相信每个消息将适合在一个单一的数据包,但是这是一个独立的问题。)

+0

感谢乔恩,但我不认为这是问题所在,我尝试了代码(遵循原来的帖子),仍然有同样的问题。 – Tony

+2

@Tony:那么,你应该基本上将问题分成两部分:序列化/反序列化协议缓冲区,并且传输数据包而不丢失任何东西(包括长度)。您应该能够重现问题* *无需使用套接字*或*而不使用协议缓冲区。毕竟,数据包只是不透明的数据位 - 它不像UDP理解它们是协议缓冲区消息。 (不管这是否是* only *问题,这当然是* a *问题。) –

+0

感谢您的即时回复Jon,我现在要尝试。 – Tony