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