gpt4 book ai didi

c - 如何检查客户端是否加入了多播组?

转载 作者:行者123 更新时间:2023-12-01 19:43:00 25 4
gpt4 key购买 nike

最终目标:

让服务器的父进程知道哪些客户端加入或离开多播组。到目前为止,我只尝试检查加入的客户,因为我认为检查离开的客户也是类似的事情。

到目前为止我的方法:

通过select()检查多播组套接字的变化。

加入后,客户端执行指向服务器程序(的父进程)的sendto()。服务器中的 select() 旨在识别任何更改,但显然没有,因此 retval != 0 永远不会为真。

到目前为止的结果

我尝试过使用许多不同的 IP 地址和常量,例如 INADDR_ANY,但我只设法通过多播将消息发送回客户端,而这个将其解释为服务器程序已发送它。最常见的结果是服务器程序根本没有收到任何消息。

这是我的客户端代码:

/* Receiver/client multicast Datagram*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_MSG 100

struct sockaddr_in localSock, servSock;
struct ip_mreq group;
int sd, n;
int datalen, mcastport;
char msg[MAX_MSG];

int main(int argc, char *argv[])
{

if(argc!=3) {
printf("usage : %s <address> <port>\n",argv[0]);
exit(0);
}

mcastport = atoi(argv[2]);


/* Create a datagram socket on which to receive. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening datagram socket....OK.\n");

/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
}

/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(mcastport);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else
printf("Binding datagram socket...OK.\n");

printf("Enter the group's name you want to join:\n");
scanf("%s", msg);

/* Join the multicast group 226.1.1.1 on the local IP address */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_multiaddr.s_addr = inet_addr(argv[1]);
group.imr_interface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(sd);
exit(1);
}
else
printf("Adding multicast group...OK.\n");

/* Initialize the group sockaddr structure with a */
/* group address of 226.1.1.1 and port given by user. */
memset((char *) &servSock, 0, sizeof(servSock));
servSock.sin_family = AF_INET;
servSock.sin_addr.s_addr = inet_addr(argv[1]);
servSock.sin_port = htons(mcastport);

if(sendto(sd, "", 1, 0, (struct sockaddr*) &servSock, sizeof(servSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");

/* Read from the socket. */
if((n=read(sd, msg, MAX_MSG)) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", msg);
}

msg[n] = '\0';

return 0;
}

这是我的服务器程序代码:

/* Send Multicast Datagram code*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>

#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy, memset */

#define MAX_MSG 100

struct in_addr localInterface;
struct sockaddr_in groupSock, cliAddr;
int sd, mcastport, maxJoin, maxJoined = 0, pipefd[2], cliLen, cpid;
char msg[MAX_MSG], groupName[MAX_MSG];

int main (int argc, char *argv[ ])
{


/* check command line args */
if(argc < 2) {
printf("usage : %s <port> \n", argv[0]);
exit(1);
}

mcastport = atoi(argv[1]);

/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK\n");

/* Initialize the group sockaddr structure with a */
/* group address of 225.1.1.1 and port given by user. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(mcastport);

printf("Create a group: ");
scanf("%s", groupName);

printf("Maximum number of clients that can join the group? ");
scanf("%d", &maxJoin);

/* Disable loopback so you do not receive your own datagrams.
{
char loopch = 0;
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0)
{
perror("Setting IP_MULTICAST_LOOP error");
close(sd);
exit(1);
}
else
printf("Disabling the loopback...OK.\n");
}
*/

/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
printf("Setting the local interface...");
localInterface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("error");
exit(1);
}
else
printf("OK\n");



if((cpid = fork()) == 0) //child process --sends messages
{
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
printf("Enter a message to send: \n");
scanf("%s", msg);

if(sendto(sd, msg, strlen(msg)+1, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");

/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/

exit(EXIT_SUCCESS);
}
else //parent process --checks for JOINs and QUITs
{
fd_set rfds;
struct timeval tv;
int retval, status;

while (waitpid(cpid, &status, WNOHANG) != cpid)
{
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sd, &rfds);

/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;

retval = select(sd+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */

if (retval == -1)
perror("select()");
else if (retval != 0)
{
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */

cliLen = sizeof(cliAddr);
int n;
if((n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr,&cliLen)) == -1)
perror("Some bullshit happened");
msg[n] = '\0';

printf("Client IP:port is: %s:%d", inet_ntoa(cliAddr.sin_addr), (int) ntohs(cliAddr.sin_port));
} else
{printf("no data.\n");}
}
exit(0);
}
return 0;
}

我还没有尝试过的可能解决方案:也许我不应该使用多播组来发送信息客户端->服务器,而是另一种类型的连接?我只是在这里猜测。我知道你们不喜欢做任何人的工作。

我已经在这个“简单”的问题上研究了几个小时,并尝试尽我所能阅读所有内容,包括 this question这看起来非常相似,但我还没有设法以任何方式解决它。我在这里完全罢工。

最佳答案

如果客户端发送到多播组并且服务器希望读取它,则服务器也需要加入多播组。

这不是一个很好的解决方案,因为所有其他客户端成员也将收到该多播。

客户端首先接收来自服务器的多播,然后响应通过结果参数提供的服务器地址会更有意义recvfrom() 的。

关于c - 如何检查客户端是否加入了多播组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33705620/

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