我试图从我的客户端服务器接收消息,虽然我没有收到任何编译错误,但我的缓冲区不会接受服务器发送的内容。我尝试更改客户端recvfrom
中的参数以与客户端sendto
中使用的参数相关联,但同样的情况发生,我的memset缓冲区仍为空。我还试过发送一个大小为2的简单的空终止char数组来测试它,并且会出现相同的结果。
服务器:
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
struct sockaddr_storage their_addr;
char buf[MAXBUFLEN];
socklen_t addr_len;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1)
perror("listener: socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("listener: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
while(1){
addr_len = sizeof their_addr;
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
buf[numbytes] = '\0';
string toRespond = theMove(buf, AG);
char * sendBack = new char[toRespond.size() + 1];
std::copy(toRespond.begin(), toRespond.end(), sendBack);
sendBack[toRespond.size()] = '\0';
sendto(sockfd, testing, strlen(testing), 0, (struct sockaddr *)&their_addr, addr_len);
}
客户端:
int sockfd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage src_addr;
socklen_t src_addr_len = sizeof(src_addr);
int rv;
int numbytes;
if (argc != 3) {
fprintf(stderr,"usage: talker hostname message\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
char * chatBuff = (char*)malloc(sizeof(char)*512);
while(1){
scanf("%s", chatBuff);
if ((numbytes = sendto(sockfd, chatBuff, strlen(chatBuff), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto");
exit(1);
}
memset(chatBuff, '\0', sizeof(chatBuff));
if (recvfrom(sockfd, chatBuff, strlen(chatBuff), 0, (struct sockaddr*)&src_addr, &src_addr_len) == -1)
{
puts("throw computer out the stacks");
}
puts(chatBuff);
freeaddrinfo(servinfo);
printf("talker: sent %d bytes to %s\n", numbytes, argv[1]);
memset(chatBuff, '\0', sizeof(chatBuff));
}
答案 0 :(得分:1)
memset(chatBuff, '\0', sizeof(chatBuff));
虽然实际上并不是错误的,但是当你打算在下一行加载它时,这个初始化整个缓冲区是一种无用的废话,并且调用了重新加载的字节数 - 这个返回将允许你确保一个空 - 通过仅设置一个字节来终止字符串。您必须记住的唯一事情是您必须为空值留出足够的空间,方法是加大缓冲区的大小或减少所请求的读取长度。
if (recvfrom(sockfd, chatBuff, strlen(chatBuff), 0, (struct sockaddr*)&src_addr, &src_addr_len) == -1)
在上面的(不必要的和浪费的)行中,您使用' sizeof(chatBuff)'作为缓冲区大小,然后在这里,莫名其妙地,你推入了#strlen(chatBuff)' - 一个RUNTIME CALL,它返回以null结尾的char数组的大小。由于您只是将该数组设置为全为null,因此它返回零,因此您的recvfrom()将始终返回一个太小的'缓冲区'除非您收到空数据报,否则会出错。
所以:
int bytesRec=recvfrom(sockfd, chatBuff, sizeof(chatBuff)-1, 0, (struct sockaddr*)&src_addr, &src_addr_len);
if(bytesRec<1) puts("throw computer out the stacks")
else chatBuff[bytesRec]=0;
答案 1 :(得分:0)
在您的服务器代码中,您将一些名为testing
的未知缓冲区作为要发送的缓冲区传递,但您应该通过sendBack
缓冲区:
sendto(sockfd, sendBack, strlen(sendBack), 0, (struct sockaddr *)&their_addr, addr_len);
就此而言,您可以取消sendBack
并直接从toRespond
发送数据:
sendto(sockfd, toRespond.c_str(), toResponse.size(), 0, (struct sockaddr *)&their_addr, addr_len);
在您的服务器和客户端代码中,您在调用AF_UNSPEC
时使用getaddrinfo()
。这在服务器中是可以的,但在客户端通常不行。想象一下,如果服务器绑定到IPv6地址会发生什么,但客户端会创建IPv4套接字,反之亦然。显然不匹配,无法进行通信(除非服务器创建可以同时接受IPv4和IPv6数据包的双栈IPv6套接字)。因此,在您的客户端代码中,您不应使用AF_UNSPEC
。使用AF_INET
或AF_INET6
,具体取决于服务器实际绑定的内容。如果您必须在客户端使用AF_UNSPEC
,则需要为每个可能的服务器IP地址调用sendto()
和recvfrom()
,直到您收到其中一个的响应为止。
最后,在您的客户端代码中,您对recvfrom()
的调用假设响应数据的大小不会与sendto()
发送的数据大小相同。实际情况是这样的吗?您没有显示theMove()
对服务器接收的数据的影响,或者它是如何生成响应的。至少,您应该在调用strlen()
时将recvfrom()
替换为512。您的客户端代码也假设服务器的响应将以空值终止,但服务器不会在它回显的数据中发送空终止符。因此,您需要终止传递给puts()
的缓冲区。