Я программирую клиент UDP. Я хочу связать сокет с данным портом на клиентской машине, так что тот же самый порт всегда используется для всех отправлений. Я получаю sockaddr для сервера, используя getaddrinfo, и я делаю то же самое, чтобы получить sockaddr, который я передаю на вызов getaddrinfo. Однако после второго вызова getaddrinfo адрес серверной машины изменяется, и я в конечном итоге отправляю пакет с клиентской машины на клиентскую машину.Значение sockaddr неожиданно изменяется после вызова getaddrinfo()
Следующий код представляет собой автономный пример, который воспроизводит ошибку:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_HOST "www.google.com"
#define UDP_PORT "4000"
static struct sockaddr_in *destination_addr = NULL;
static int client_port;
int main(){
uint8_t bytes[5] = { 0xaa, 0xab, 0xac, 0xad, 0xaf}; //some data to send
uint16_t length = 5;
int status;
//initialize socket and bind
if (destination_addr == NULL) {
struct addrinfo hints;
struct addrinfo *servinfo, *p;
srand(time(NULL));
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(SERVER_HOST, UDP_PORT, &hints, &servinfo)) != 0) {
printf("Unable to send UDP. Reason: %s", gai_strerror(status));
return 0;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if (p->ai_addr != NULL)
destination_addr = (struct sockaddr_in *) p->ai_addr;
}
client_port = 1027 + rand()%50000;
freeaddrinfo(servinfo);
printf("Created destination_addr with IP %s\n", inet_ntoa(destination_addr->sin_addr));
}
int send_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (send_socket_fd == -1) {
printf("Unable to create UDP socket. Reason: %s", strerror(errno));
return 0;
}
printf("IP after socket creation is %s\n", inet_ntoa(destination_addr->sin_addr));
int yes = 1;
if (setsockopt(send_socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1) {
perror("setsockopt");
return 0;
}
printf("IP after sockopt is %s\n", inet_ntoa(destination_addr->sin_addr));
// bind to local address
char str_client_port[6];
snprintf(str_client_port, 5, "%d", client_port);
struct addrinfo *source_addr_info;
struct addrinfo hints;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
// ***** destination_addr changes after this call *****
getaddrinfo (NULL, str_client_port, &hints, &source_addr_info);
printf("IP after getaddrinfo is %s\n", inet_ntoa(destination_addr->sin_addr));
bind(send_socket_fd, source_addr_info->ai_addr, source_addr_info->ai_addrlen);
printf("IP after binding is %s\n", inet_ntoa(destination_addr->sin_addr));
// send
int bytes_sent = sendto(send_socket_fd, bytes, length, 0, (struct sockaddr *)destination_addr, sizeof *destination_addr);
printf("Sent to IP %s\n", inet_ntoa(destination_addr->sin_addr));
if (bytes_sent != length){
if (bytes_sent == -1){
printf("UDP send failed. Reason: %s", strerror(errno));
}
else {
printf("UDP: not all bytes could be sent.");
}
}
close(send_socket_fd);
return 1;
}
Выход генерируется посредством выполнения этой программы в моей машине:
Created destination_addr with IP 64.233.167.105
IP after socket creation is 64.233.167.105
IP after sockopt is 64.233.167.105
IP after getaddrinfo is 0.0.0.0
IP after binding is 0.0.0.0
Sent to IP 0.0.0.0
Я довольно новый в гнездо программирование на C, и я уверен, что я делаю какую-то глупую ошибку, но после многого поиска и много чего пытаюсь, я все еще придерживаюсь этого. Есть идеи?
Ну, конечно, это меняется. Это то, что функция должна делать. Перед тем, как вы получите новый адрес, вы должны связать его со старым адресом. Или используйте две структуры адресов. Неужели это очевидно? – EJP
Я сомневаюсь, что 'p-> ai_addr' (a.k.a.' destination_addr') является допустимым указателем после 'freeaddrinfo'. – molbdnilo
@EJP Я использую две структуры адресов: 'destination_addr' и' source_addr_info-> ai_addr'. Не должно быть причин, по которым вызов 'getaddrinfo' в' source_addr_info' должен изменить значение 'destination_addr'. Если, как указывает @molbdnilo, память, освобожденная 'freeaddrinfo', перезаписывается вызовом' getaddrinfo'. Я буду следовать этому пути для решения проблемы. – joanlofe