gpt4 book ai didi

c - C : Binary does not receive when using addrinfo 中的多播

转载 作者:太空宇宙 更新时间:2023-11-03 23:46:37 25 4
gpt4 key购买 nike

我在两个几乎相同的程序中遇到了这个有趣的小问题。我想做的是在多播套接字上发送一些数据并接收它。现在,如果发件人收到消息,我就没问题(我会将选项设置为稍后不接收)。

我有两个实现案例。在第一种方法中,我使用传统方法初始化 sockaddr 结构,然后绑定(bind)到同一套接字上的多播组。然而,这依赖于 IPv4/IPv6,为了避免这种情况,我尝试在程序的第二个变体中使用 addrinfo 结构。下面给出了这两个程序。

问题是,在第一个用例中正在接收消息,我使用的是常规 sockaddr,而在第二个用例中没有接收到消息/设置套接字描述符。有人可以帮我解释一下为什么会这样吗?

变体 1(使用 sockaddr)

#include<stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h> /* for nonblocking */
#include <netinet/tcp.h>

fd_set hm_tprt_conn_set;

main()
{
struct ip_mreq mreq;
struct sockaddr_in mc_addr;
int sock_fd ;
int val;
int reuse = 1;

struct sockaddr_in ip;
struct sockaddr_in src_addr;

int total_bytes_rcvd=0;
unsigned int length;
unsigned char buf[50];
int op_complete = 0;
int os_error;

struct timeval select_timeout;
fd_set read_set;
int32_t nready; //Number of ready descriptors

time_t time_val;

length = sizeof (src_addr);

sock_fd = socket(AF_INET, SOCK_DGRAM,0);
if(sock_fd == -1)
{
printf("\n Error Opening UDP MCAST socket");
perror("\n Cause is ");
exit(0);
}

printf("\n Setting the socket to non-blocking mode");
val = fcntl(sock_fd, F_GETFL , 0);
val = fcntl(sock_fd, F_SETFL, val | O_NONBLOCK);

if (val == -1)
{
printf("\n Error while setting socket to non-blocking mode");
perror("Cause is ");
sock_fd = -1;
exit(0);
} //end if val == -1

if (setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}

FD_SET(sock_fd, &hm_tprt_conn_set);

printf("\n Construct a mcast address structure");
/* construct a multicast address structure */

memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
mc_addr.sin_port = htons(4936);

memset(&ip, 0, sizeof(ip));
ip.sin_family = AF_INET;
ip.sin_addr.s_addr = inet_addr("224.0.0.203")/*htonl(INADDR_ANY)*/;
ip.sin_port = htons(4936);

printf("\n Bind the multicast address structure and port to the recieving socket ");
if (bind( sock_fd, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1)
{
fprintf(stderr, "bind: %d\n", errno);
perror("\n Cause is ");
exit(0);
}

mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.203");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);

if(setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("\n Cause is ");
exit(0);
}

printf("\nCreated Recv Socket: %d", sock_fd);


fflush(stdout);
memset(&src_addr, 0, sizeof(mc_addr));
while(1){
/* Send a multicast */
time_val = time(NULL);
snprintf(buf, sizeof(buf), "Hello: %s", ctime(&time_val));
total_bytes_rcvd = sendto(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&ip,
length );
printf("\n%d bytes sent.", total_bytes_rcvd);

/* perform select */
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 5000000;

read_set = hm_tprt_conn_set;

nready = select(sock_fd+1, &read_set, NULL, NULL, &select_timeout);
if(nready == 0)
{
/***************************************************************************/
/* No descriptors are ready */
/***************************************************************************/
continue;
}
else if(nready == -1)
{
perror("Error Occurred on select() call.");
continue;
}

if(FD_ISSET(sock_fd, &read_set))
{
printf("\n Recv the data");
total_bytes_rcvd = recvfrom(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&src_addr,
&length );

printf("%s: message = \" %s \"\n", inet_ntoa(src_addr.sin_addr), buf);
printf("\n total byte recieved %d", total_bytes_rcvd);

/***************************************************************************/
/* If select returned 1, and it was a listen socket, it makes sense to poll*/
/* again by breaking out and use select again. */
/***************************************************************************/
if(--nready <=0)
{
printf("\nNo more incoming requests.");
continue;
}
}//end select on listenfd
}
}

变体 2(使用 addrinfo)

#include<stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h> /* for nonblocking */
#include <netinet/tcp.h>
#include <netdb.h> /* AI_PASSIVE and other Macros for getaddrinfo() */

fd_set hm_tprt_conn_set;

main()
{

struct addrinfo hints, *res, *ressave;
char target[128] = "127.0.0.1";
char service[128] = "4936";

struct ip_mreq mreq;

int sock_fd ;
int val;
int reuse = 1;

struct sockaddr_in ip;
struct sockaddr_in src_addr;

int total_bytes_rcvd=0;
unsigned int length;
unsigned char buf[50];
int op_complete = 0;
int os_error;

struct timeval select_timeout;
fd_set read_set;
int32_t nready; //Number of ready descriptors

time_t time_val;

length = sizeof (src_addr);

sock_fd = socket(AF_INET, SOCK_DGRAM,0);
if(sock_fd == -1)
{
printf("\n Error Opening UDP MCAST socket");
perror("\n Cause is ");
exit(0);
}

printf("\n Setting the socket to non-blocking mode");
val = fcntl(sock_fd, F_GETFL , 0);
val = fcntl(sock_fd, F_SETFL, val | O_NONBLOCK);

if (val == -1)
{
printf("\n Error while setting socket to non-blocking mode");
perror("Cause is ");
sock_fd = -1;
exit(0);
} //end if val == -1

if (setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}

FD_SET(sock_fd, &hm_tprt_conn_set);

printf("\n Construct a mcast address structure");
/* construct a multicast address structure */

hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;

if((os_error = getaddrinfo(target, service, &hints, &res)) !=0)
{
printf("\n%s",gai_strerror(os_error));
exit(0);
}

ressave = res;

if(bind(sock_fd, res->ai_addr, res->ai_addrlen) != 0)
{
perror("Error binding to port");
close(sock_fd);
sock_fd = -1;
}

mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.203");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);

if(setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}

/* Set Destination address */
memset(&ip, 0, sizeof(ip));
ip.sin_family = AF_INET;
ip.sin_addr.s_addr = inet_addr("224.0.0.203")/*htonl(INADDR_ANY)*/;
ip.sin_port = htons(4936);

/* Set to zero address where addresses of sender will be received */
memset(&src_addr, 0, sizeof(src_addr));

while(1){

/* Send a multicast */
time_val = time(NULL);
snprintf(buf, sizeof(buf), "Hello: %s", ctime(&time_val));
total_bytes_rcvd = sendto(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&ip,
length );

printf("\n%d bytes sent.", total_bytes_rcvd);

/* perform select */
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 5000000;

read_set = hm_tprt_conn_set;

nready = select(sock_fd+1, &read_set, NULL, NULL, &select_timeout);
if(nready == 0)
{
/***************************************************************************/
/* No descriptors are ready */
/***************************************************************************/
continue;
}
else if(nready == -1)
{
perror("Error Occurred on select() call.");
continue;
}

if(FD_ISSET(sock_fd, &read_set))
{
printf("\n Recv the data");
total_bytes_rcvd = recvfrom(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&src_addr,
&length );

printf("%s: message = \" %s \"\n", inet_ntoa(src_addr.sin_addr), buf);
printf("\n total byte recieved %d", total_bytes_rcvd);

/***************************************************************************/
/* If select returned 1, and it was a listen socket, it makes sense to poll*/
/* again by breaking out and use select again. */
/***************************************************************************/
if(--nready <=0)
{
printf("\nNo more incoming requests.");
continue;
}
}//end select on listenfd
}
}

最佳答案

不同之处在于,在第一个变体中,您绑定(bind)到 INADDR_ANY,而在第二个变体中,您绑定(bind)到 127.0.0.1。未能绑定(bind)到 INADDR_ANY 意味着您不会收到任何多播数据。

您可以通过以下方式解决此问题:

hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;

if((os_error = getaddrinfo(NULL, service, &hints, &res)) !=0)
{
printf("\n%s",gai_strerror(os_error));
exit(0);
}

来自关于 AI_PASSIVE 的 getaddrinfo 的手册页:

If node is NULL, the network address in each socket structure is initialized according to the AI_PASSIVE flag, which is set in hints.ai_flags. The network address in each socket structure will be left unspecified if AI_PASSIVE flag is set. This is used by server applications, which intend to accept client connections on any network address. The network address will be set to the loopback interface address if the AI_PASSIVE flag is not set. This is used by client applications, which intend to connect to a server running on the same network host.

虽然在这种情况下您发送到同一台主机,但默认情况下多播数据不会在本地主机接口(interface)上发出。您需要使用 IP_MULTICAST_IF 选项调用 setsockopt 以设置传出多播接口(interface)。

通过此更改,我能够使用第二个变体发送和接收。

关于c - C : Binary does not receive when using addrinfo 中的多播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31044546/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com