C 套接字地址显示0.0.0.0,导致无法发送消息
我一直在使用Beejs网络示例,介绍一些定制。特别是,我尝试使用一个结构来存储与通信/套接字相关的必要信息。我想我在填充C 套接字地址显示0.0.0.0,导致无法发送消息,c,sockets,network-programming,getaddrinfo,C,Sockets,Network Programming,Getaddrinfo,我一直在使用Beejs网络示例,介绍一些定制。特别是,我尝试使用一个结构来存储与通信/套接字相关的必要信息。我想我在填充addrinfo结构并将其与UDP套接字的sendto一起使用时遇到了问题。下面是我的代码,它编译得很好,但是它失败了,下面列出了一条消息 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/
addrinfo
结构并将其与UDP套接字的sendto
一起使用时遇到了问题。下面是我的代码,它编译得很好,但是它失败了,下面列出了一条消息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// Definitions
#define COM_MSG_SIZE 1024
#define COM_HOST_SIZE 128
struct com_socket
{
char *type;
int descriptor;
struct addrinfo addr;
};
void COM_error(char *msg) {
perror(msg);
exit(0);
}
int main()
{
int status;
struct com_socket COM_client;
char addr_str[COM_HOST_SIZE];
// ---------------------------------------------
// Initialize socket
COM_client.type = "UDP";
char *hostname = "192.168.0.110";
char *port_num = "4000";
printf("Creating socket...");
if(strcmp(COM_client.type, "UDP") == 0)
{
COM_client.descriptor = socket(AF_INET, SOCK_DGRAM, 0);
}
// Error check
if(COM_client.descriptor < 0)
{
COM_error(" ERROR opening socket");
}
printf(" Success\n");
//------------------------------------------------------------------------------------------
// Define hints
struct addrinfo hints;
hints.ai_family = AF_INET; // AF_UNSPEC "unspecified" or can use IPv6 = AF_INET6, IPv4 = AF_INET
hints.ai_socktype = SOCK_DGRAM; // Socket type: SOCK_STREAM or SOCK_DGRAM or 0 = auto
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = 0; // 0 = auto
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_addrlen = 0;
hints.ai_next = NULL;
// Get the linked list of address info
struct addrinfo *host_list;
printf("Building host address list...");
status = getaddrinfo(hostname,port_num,&hints,&host_list);
// returns 0 if succeeds
if (status != 0)
{
COM_error(" ERROR getaddrinfo: %s\n");
}
printf(" Success\n");
//------------------------------------------------------------------------------------------
// Select address
int count = 1;
struct addrinfo *entry;
// Loop through each entry in the "linked list" and pull the necessary one
for (entry = host_list; entry != NULL; entry = entry->ai_next)
{
// Print the list of potential IP addresses
if( NULL == inet_ntop( AF_INET, &((struct sockaddr_in *) entry->ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) )
{
COM_error(" ERROR with inet_ntop\n");
}
printf(" Address entry %d: %s",count,addr_str);
// Update counter
count = count + 1;
// Choose which one to copy
if(strncmp(addr_str,"192.",(size_t) 4) == 0)
{
//memcpy(COM_client.addr,entry, sizeof(struct addrinfo));
COM_client.addr = *entry;
// COM_client.addr.ai_addr = entry->ai_addr;
// COM_client.addr.ai_addrlen = entry->ai_addrlen;
// COM_client.addr.ai_canonname = entry->ai_canonname;
// COM_client.addr.ai_family = entry->ai_family;
// COM_client.addr.ai_flags = entry->ai_flags;
// COM_client.addr.ai_protocol = entry->ai_protocol;
// COM_client.addr.ai_socktype = entry->ai_socktype;
if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
{
COM_error(" ERROR with arguments to inet_ntop\n");
}
printf(" <--------- selected* (%s) \n",addr_str);
break;
}
else
{
printf("\n");
}
}
// Clean
freeaddrinfo(host_list);
//-------------------------------------------------------
char *buffer;
char msg[COM_MSG_SIZE];
strncpy(msg,"BEGIN",COM_MSG_SIZE);
printf("ENTER `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
buffer = calloc(COM_MSG_SIZE+1, sizeof(char));
printf("AFTER calloc `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
// Check to see if we were successful
if (buffer == NULL)
{
printf("ERROR Could not allocate required memory\n");
exit(1);
}
// Copy message to buffer
strncpy(buffer,msg,COM_MSG_SIZE);
printf("Message input: %s Message to be sent: %s\n",msg,buffer);
if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
{
COM_error(" ERROR with arguments to inet_ntop\n");
}
printf("SEND to address (%s) \n",addr_str);
// Send the buffer to the destination address
if(strcmp(COM_client.type, "UDP") == 0)
{
status = sendto(COM_client.descriptor, buffer, strlen(buffer), 0, COM_client.addr.ai_addr, COM_client.addr.ai_addrlen);
// Error check
if (status < 0)
{
COM_error("ERROR could not send message");
}
}
// Free buffer memory
free(buffer);
//---------------------------------------------------------
close(COM_client.descriptor);
return 0;
}
正如你所看到的,我尝试过各种方法,但都失败了。我想继续使用COM\u客户端
结构方法,因为我的目的是使代码更加模块化,这样我可以传递包含所有必要通信信息的结构。这一行
COM_client.addr = *entry;
“尝试”复制一个结构addrinfo
,它实际上是这样做的,但因为它包含指针,“仅”复制指针的值。这些指针指向的内存已由getaddrinfo()
分配,因此将通过调用freeaddrinfo()
释放,之后将指针留在副本悬挂中
要解决这个问题,您需要执行struct addrinfo
的“深度复制”
例如,可以这样做:
/* Does a deep copy to where pdst point from where pscr points to.
Returns 0 on success and -1 on error. Sets errno. */
int addrinfo_copy(struct addrinfo * pdst, struct addrinfo * psrc)
{
int result = 0; /* Be optimistic. */
assert(pdst);
assert(psrc);
*pdst = *pscr; /* Copy all. Note that the pointer elements copied
need to be recreated. See below ... */
do
{
pdst->ai_addr = malloc(psrc->ai_addrlen);
if (!pdst->ai_addr)
{
result = -1;
break;
}
memcpy(pdst->ai_addr, psrc->ai_addr, psrc->ai_addrlen);
pdst->ai_canonname = strdup(psrc->ai_canonname); /* Assumes POSIX. */
if (!pdst->ai_canonname)
{
result = -1;
break;
}
} while (0);
return result;
}
要摆脱这样的副本,您需要以下内容:
/* Deallocates and sets to a 0/NULL what had been created by
addrinfo_copy(). */
void addrinfo_free(struct addrinfo * p)
{
assert(p);
free(p->ai_addr);
free(p->canonname);
memset(p, 0, sizeof *p); /* In fact not necessary. */
}
struct addrinfo * entry, * entry_copy;
/* Set entry to something returned by getaddrinfo (). */
...
if (-1 = addrinfo_copy(entry_copy, entry))
{
perror("addrinfo_copy() failed"):
exit(EXIT_FAILURE);
}
/* Deallocate all results returned by getaddrinfo(). */
freeaddrinfo(...);
/* Still use entry_copy here. */
...
/* Clean up. */
addrinfo_free(entry_copy);
像这样使用它:
/* Deallocates and sets to a 0/NULL what had been created by
addrinfo_copy(). */
void addrinfo_free(struct addrinfo * p)
{
assert(p);
free(p->ai_addr);
free(p->canonname);
memset(p, 0, sizeof *p); /* In fact not necessary. */
}
struct addrinfo * entry, * entry_copy;
/* Set entry to something returned by getaddrinfo (). */
...
if (-1 = addrinfo_copy(entry_copy, entry))
{
perror("addrinfo_copy() failed"):
exit(EXIT_FAILURE);
}
/* Deallocate all results returned by getaddrinfo(). */
freeaddrinfo(...);
/* Still use entry_copy here. */
...
/* Clean up. */
addrinfo_free(entry_copy);
最后,请注意:
如果在使用C语言时,您观察到内存内容发生了模糊的突然/意外变化,那么这一切都是由于写入和/或读取“错误”内存而导致内存管理混乱所致。有些时候,在内存中的这些变化变得明显和/或代码中的这些变化(似乎)与您在内存中观察到的这些变化完全无关之前很久,这种情况就发生了。请记住,自C99以来,您可以(几乎)在任何地方声明变量,从而允许代码可读。请这不是一个简单的例子。删除注释代码、未使用的变量等!您想使用内存检查器运行代码,如。@Stargateur我移动了一些变量声明
struct addrinfo
包含指针。因此,在复制这样一个结构时,您需要执行深度复制,这意味着适当地分配内存。