套接字 sendto() returns EINVAL 在上一次成功调用之后
Sockets sendto() returns EINVAL after previous successful call
我修改了 this C 数据报 (UDP) 套接字客户端示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#define SERVERPORT "4950"
volatile sig_atomic_t is_shutdown = 0;
void handler_signal(int signal)
{
if (signal == SIGINT)
{
is_shutdown = 1;
}
}
int main(int argc, char *argv[])
{
int socket_fd;
struct addrinfo hints, *server_info, *temp;
int result;
int number_bytes;
if (argc != 2)
{
fprintf(stderr, "usage: executable [hostname]\n");
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
result = getaddrinfo(argv[1], SERVERPORT, &hints, &server_info);
if (result != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return 1;
}
// loop through all the results and make a socket
for(temp = server_info; temp != NULL; temp = temp->ai_next)
{
socket_fd = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol);
if (socket_fd == -1)
{
fprintf(stderr, "socket error: %s\n", strerror(errno));
continue;
}
break;
}
freeaddrinfo(server_info);
if (temp == NULL)
{
fprintf(stderr, "failed to create socket\n");
return 2;
}
//int hostname_length = strlen(argv[2]);
unsigned long counter = 0;
const size_t buffer_length = 50;
char buffer[buffer_length];
memset(&buffer, 0, buffer_length);
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, temp->ai_addr, temp->ai_addrlen);
if (number_bytes == -1)
{
fprintf(stderr, "sendto error: %s\n", strerror(errno));
break;
}
printf("sent %d bytes to %s.\n", number_bytes, argv[1]);
}
result = close(socket_fd);
if (result == -1)
{
fprintf(stderr, "close error: %s\n", strerror(errno));
}
printf("exiting application\n");
return 0;
}
它在 sendto
函数和 Invalid argument (errno 22)
的第二次循环迭代中失败。它适用于第一个。
但是,如果我将其更改为以下代码,则代码有效(客户端在无限循环中不断发送消息并且服务器成功接收它们):
//...
//create a copy to pass it later
socklen_t length = temp->ai_addrlen;
struct sockaddr *address = temp->ai_addr;
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, address, length);
//...
我在这里做了什么?我错过了什么?我不确定这里发生了什么。
正如Frankie_C在他的[评论]中指出的那样:
temp
是指向 struct addrinfo
的指针,它的值是从 server_info
赋值的。但是当你 freeaddrinfo(server_info)
内存被释放并且 temp
指向任何地方。它第一次工作是因为还没有发生内存重用。但是在内存重用后它就失效了。尝试在释放结构之前制作数据副本。
我修改了 this C 数据报 (UDP) 套接字客户端示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#define SERVERPORT "4950"
volatile sig_atomic_t is_shutdown = 0;
void handler_signal(int signal)
{
if (signal == SIGINT)
{
is_shutdown = 1;
}
}
int main(int argc, char *argv[])
{
int socket_fd;
struct addrinfo hints, *server_info, *temp;
int result;
int number_bytes;
if (argc != 2)
{
fprintf(stderr, "usage: executable [hostname]\n");
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
result = getaddrinfo(argv[1], SERVERPORT, &hints, &server_info);
if (result != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return 1;
}
// loop through all the results and make a socket
for(temp = server_info; temp != NULL; temp = temp->ai_next)
{
socket_fd = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol);
if (socket_fd == -1)
{
fprintf(stderr, "socket error: %s\n", strerror(errno));
continue;
}
break;
}
freeaddrinfo(server_info);
if (temp == NULL)
{
fprintf(stderr, "failed to create socket\n");
return 2;
}
//int hostname_length = strlen(argv[2]);
unsigned long counter = 0;
const size_t buffer_length = 50;
char buffer[buffer_length];
memset(&buffer, 0, buffer_length);
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, temp->ai_addr, temp->ai_addrlen);
if (number_bytes == -1)
{
fprintf(stderr, "sendto error: %s\n", strerror(errno));
break;
}
printf("sent %d bytes to %s.\n", number_bytes, argv[1]);
}
result = close(socket_fd);
if (result == -1)
{
fprintf(stderr, "close error: %s\n", strerror(errno));
}
printf("exiting application\n");
return 0;
}
它在 sendto
函数和 Invalid argument (errno 22)
的第二次循环迭代中失败。它适用于第一个。
但是,如果我将其更改为以下代码,则代码有效(客户端在无限循环中不断发送消息并且服务器成功接收它们):
//...
//create a copy to pass it later
socklen_t length = temp->ai_addrlen;
struct sockaddr *address = temp->ai_addr;
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, address, length);
//...
我在这里做了什么?我错过了什么?我不确定这里发生了什么。
正如Frankie_C在他的[评论]中指出的那样:
temp
是指向 struct addrinfo
的指针,它的值是从 server_info
赋值的。但是当你 freeaddrinfo(server_info)
内存被释放并且 temp
指向任何地方。它第一次工作是因为还没有发生内存重用。但是在内存重用后它就失效了。尝试在释放结构之前制作数据副本。