我知道这可能很愚蠢,但我使用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的协议缓冲区,除非你有充分的理由相信每条消息都适合单个数据包,但这是另一回事.)
我怀疑这是问题所在:
strcpy(Sentence, array);
你正在使用strcpy
- 一旦它到达0字节就会停止,因为它将这个有点任意的二进制数据视为一个字符串.我怀疑你应该使用memcpy
.
同样,以后不要使用strlen.避免将数据视为文本的所有函数.
(一般情况下,我要小心使用带有UDP的协议缓冲区,除非你有充分的理由相信每条消息都适合单个数据包,但这是另一回事.)