简单的多播应用程序无法在同一网络上的其他计算机上运行 [英] simple multicast app not working on different computer on the same network

查看:100
本文介绍了简单的多播应用程序无法在同一网络上的其他计算机上运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 如果我在同一台计算机上启动以下2个代码实例,则组播工作正常.
  • 如果我在同一网络中的另一台计算机上启动它,则不会收到任何信息.

有什么主意吗?此代码应按原样编译.

Any idea what could be wrong? This code should compile as is.

我正在win10上进行测试,但是在linux上运行时却得到类似的结果.

I am testing on win10 but I get similar results when I run this on linux.

#include "pch.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "winsock2.h"
#include <iostream>
#include <conio.h>
#include <thread>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

char mcastGroup[] = "224.1.2.3";
int mcastPort = 5435;

int CreateSocket()
{
    return socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}

void JoinGroup(int sck)
{
    struct ip_mreq grp;
    grp.imr_multiaddr.s_addr = inet_addr(mcastGroup);
    grp.imr_interface.s_addr = htonl(INADDR_ANY);

    if (setsockopt(sck, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&grp, sizeof(grp)) < 0)
    {
        printf("Error in joining group\n");
        closesocket(sck);
        exit(1);
    }
}

int receiver()
{
     int sck = CreateSocket();

    int reuse = 1;
    if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
    {
        perror("Socket reuse address error\n");
        closesocket(sck);
        exit(1);
    }

    JoinGroup(sck);

    struct sockaddr_in lclSck;
    memset((char *)&lclSck, 0, sizeof(lclSck));
    lclSck.sin_family = AF_INET;
    lclSck.sin_port = htons(mcastPort);
    lclSck.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sck, (struct sockaddr*)&lclSck, sizeof(lclSck)))
    {
        perror("Error in binding socket\n");
        closesocket(sck);
        exit(1);
    }

    while (1)
    {
        int blen;
        char buf[1024];
        blen = sizeof(buf);
        memset(buf, 0, blen);

        struct sockaddr_in addrin;
        int addrinlen = sizeof(addrin);
        memset(&addrin, 0, sizeof(addrin));
        int res = recvfrom(sck, buf, blen, 0, (sockaddr *)&addrin, &addrinlen);
        if (res<0)
        {
            printf("Message read error\n");
            closesocket(sck);
            exit(1);
        }
        else
        {
            printf(": %s\n", buf);
        }

    }
    return 0;
}

int sender()
{
    int sck = CreateSocket();

    struct in_addr lclInterface;
    lclInterface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sck, IPPROTO_IP, IP_MULTICAST_IF, (char *)&lclInterface, sizeof(lclInterface)) < 0)
    {
        printf("Local interface error\n");
        exit(1);
    }
    else
    {
        printf("Local interface set\n");
    }

    u_char ttl = 5;
    setsockopt(sck, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl));

    while (1)
    {
        int blen;
        char buf[1024];
        blen = sizeof(buf);
        memset(buf, 0, blen);

        for (int i = 0; i < 100; i++)
        {
            fgets(buf, blen, stdin);

            sockaddr_in grpSck;
            memset((char *)&grpSck, 0, sizeof(grpSck));
            grpSck.sin_family = AF_INET;
            grpSck.sin_port = htons(mcastPort);
            grpSck.sin_addr.s_addr = inet_addr(mcastGroup);
            if (sendto(sck, buf, blen, 0, (struct sockaddr*)&grpSck, sizeof(grpSck)) < 0)
            {
                printf("Error in sending message");
            }
        }
    }
    return 0;
}

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    std::thread t1([&] { receiver(); return 0; });   
    sender();

    WSACleanup();
}

推荐答案

此代码应该可以工作,问题是我使用的是IP_MULTICAST_IF,它强制使用与默认接口不同的网络接口.万一需要使用这样的东西,我可以通过以下方式使多播工作 感谢Remy Lebeau的建议,这是确保将套接字绑定到同一网络中的IP.

This code should work, the problem was that I was using IP_MULTICAST_IF, that forces to use a network interface different from the default one. In case one needs to use such a thing I was able to get the multicast working by following Thanks to Remy Lebeau advice, that is to make sure you are binding the sockets to IPs that are in the same network.

以下是工作代码:

#ifdef WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")

#else
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

#endif

#include <thread>

char mcastGroup[] = "224.1.2.3";
int mcastPort = 5435;

void PrintAddrIn(sockaddr_in addr_in)
{
    char str[255];
    inet_ntop(AF_INET, &addr_in.sin_addr, (char *)str, sizeof(str));
    printf("%s", str);
}

int receiver(int sck)
{
    while (1)
    {
        char buf[1024];
        memset(buf, 0, sizeof(buf));

        struct sockaddr_in addrin;
        socklen_t addrinlen = sizeof(addrin);
        memset(&addrin, 0, sizeof(addrin));
        int res = recvfrom(sck, buf, sizeof(buf), 0, (sockaddr *)&addrin, &addrinlen);
        if (res<0)
        {
            printf("Message read error\n");
            exit(1);
        }
        else
        {
            PrintAddrIn(addrin); printf(": %s\n", buf);
        }
    }
    return 0;
}

int sender(int sck)
{
    while (1)
    {
        sockaddr_in grpSck;
        memset((char *)&grpSck, 0, sizeof(grpSck));
        grpSck.sin_family = AF_INET;
        grpSck.sin_port = htons(mcastPort);
        grpSck.sin_addr.s_addr = inet_addr(mcastGroup);

        for (int i = 0; i < 100; i++)
        {
            char buf[1024];
            fgets(buf, sizeof(buf), stdin);

            if (sendto(sck, buf, strlen(buf), 0, (struct sockaddr*)&grpSck, sizeof(grpSck)) < 0)
            {
                printf("Error in sending message");
                exit(1);
            }
        }
    }
    return 0;
}

int main()
{
#ifdef WIN32
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

    int sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    // Set reuse
    //
    int reuse = 1;
    if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
    {
        perror("Socket reuse address error\n");
        exit(1);
    }
    else
    {
        printf("Socket reuse address successfull\n");
    }

    // Join mcast group
    //
    struct ip_mreq grp;
    grp.imr_multiaddr.s_addr = inet_addr(mcastGroup);
    grp.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sck, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&grp, sizeof(grp)) < 0)
    {
        printf("Error in joining group\n");
        exit(1);
    }
    else
    {
        printf("Group joined successfully\n");
    }

    // Bind socket
    //
    struct sockaddr_in lclSck;
    memset((char *)&lclSck, 0, sizeof(lclSck));
    lclSck.sin_family = AF_INET;
    lclSck.sin_port = htons(mcastPort);
    lclSck.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sck, (struct sockaddr*)&lclSck, sizeof(lclSck)))
    {
        perror("Error in binding socket\n");
        exit(1);
    }
    else
    {
        printf("Socket binding successfull\n");
    }

    u_char ttl = 5;
    setsockopt(sck, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl));

    std::thread t1([&] { receiver(sck); return 0; });

    sender(sck);

#ifdef WIN32
    WSACleanup();
#endif
}

这篇关于简单的多播应用程序无法在同一网络上的其他计算机上运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆