2011-12-05 10 views
4

私は愚かかもしれないが、Googleのプロトコルバッファで定義された私のメッセージパックは、TCPと完全にUDPを使ってうまく動作していないことを知っています。 クライアントからサーバーにUDPを介してシリアル化されたパッケージ(通常のフィールドしかない)から通常の文字列を送信すると、すべてのことがうまくいきます。しかし、繰り返しフィールドを追加すると、シリアル化された文字列は全体の一部しか受信できませんでした。最初のフィールドは完全に受信されますが、残りのフィールドはすべて失われます。 コードはC++、Googleプロトコルバッファ2.3.0、Linuxで書かれています。 助けを歓迎します。おかげさまで Googleプロトコルバッファは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を使用しないでください。データをテキストとして扱うすべての関数を避けてください。

(一般的には、各メッセージが単一のパケットに収まると信じる十分な理由を持っていない限り、私はUDPでプロトコルバッファを使用しての警戒すると思いますが、それは別の問題です。)

+0

ありがとうジョン、しかし私はそれが問題だとは思わない、私はコードを(元の投稿に続いて)しようと、同じ問題がまだあります。 – Tony

+2

@トニー:基本的には、問題をプロトコルバッファのシリアライズ/デシリアライズとデータパケットの転送(長さを含む)の2つに分割する必要があります。プロトコルバッファーを使用せずにソケット*または*を使用せずに問題を再現できるはずです。結局のところ、パケットは単なるデータの不透明なビットです。つまり、UDPのようにプロトコルバッファメッセージではないということです。 (そして、これが*唯一の問題かどうかは、確かに問題でした) –

+0

あなたのすぐ返事をありがとうJon、私は今しようとします。 – Tony

関連する問題