UDP广播正在发送,但未收到 [英] UDP broadcast being sent, but not received

查看:257
本文介绍了UDP广播正在发送,但未收到的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个非常简单的游戏大厅系统。每个客户端以规律的间隔通过UDP广播两个分组,以初始发现其他客户端并传输用户信息,准备等。游戏正在为Windows和Linux(32和64位)开发。

I'm working on a very simple lobby system for a game. Each client broadcasts two packets via UDP at regular intervals to initially discover other clients and transmit user info, readiness, etc. The game is being developed for both Windows and Linux (32 & 64 bit).

在Windows方面,我已经使大厅系统工作正常。当我在一台Windows机器上进入大厅时,该人在其他机器中弹出。类似地,立即检测到就绪检查和断开连接。换句话说,它工作。

On the Windows side, I've gotten the lobby system working flawlessly. When I enter the lobby on one Windows machine, the person pops up in the other machines. Similarly, ready checks and disconnects are detected right away. In other words, it works.

现在的问题:Linux。网络代码实际上是相同的,只有几个必要的平台特定的更改。我第一次尝试Windows < - > Linux。使用Wireshark,我发现Linux端确实是广播数据包,并从Windows框中接收它们,但游戏从来没有捕获到数据包。我在我的选择语句(套接字,而不是套接字+ 1)中发现一个错误,但修复它没有帮助。 Windows盒子正在广播数据包,但它没有从Linux盒子接收数据包!

Now the problem: Linux. The network code is virtually identical, with only a few necessary platform-specific changes. I first tried Windows<->Linux. Using Wireshark, I found that the Linux side was indeed broadcasting packets and receiving them from the Windows box, but the game never caught the packets. I found a bug in my select statement (socket instead of socket + 1), but fixing it didn't help. The Windows box was broadcasting packets, but it wasn't receiving packets from the Linux box at all!

然后我尝试Linux - Linux,但发现即使两台机器都广播和接收(再次,通过Wireshark确认),两台机器上的游戏不能看到数据包。

I then tried Linux<->Linux, but found that even though both machines were broadcasting and receiving (again, confirmed via Wireshark), the games on both machines couldn't "see" the packets.

我确定它不是一个防火墙问题(关闭所有关闭,测试,将一切重新启动,没有改变,在任何平台上)和网络连接似乎确定(手动ping每个主机)。

I'm pretty sure it's not a firewall issue (turned everything off, tested, turned everything back on, no change, on either platform) and network connectivity seems ok (was able to ping each host manually). I also checked to make sure the ports were indeed available (they were).

以下是广播数据包的代码:

Below is the code for broadcasting packets:

    void NetworkLinux::BroadcastMessage(const std::string &msg,
            const char prefix)
    {
        string data(prefix + msg);

        if (sendto(linuxSocket, data.c_str(), static_cast<int>(data.length()), 0,
        reinterpret_cast<sockaddr*>(&broadcastAddr), sizeof(broadcastAddr)) == -1)
        {
            Display_PError("sendto");
        }
    }

接收数据包的代码:

const Message NetworkLinux::ReceiveMessage()
    {
        char buffer[recvBufferLength];
        fill(buffer, buffer + recvBufferLength, 0);
        sockaddr_in sender;
        int senderLen = sizeof(sender);

        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(linuxSocket, &read_fds);

        timeval time;
        time.tv_sec = 0;
        time.tv_usec = 16667; // microseconds, so this is ~1/60 sec

        int selectResult = select(linuxSocket + 1, &read_fds, 
                                      nullptr, nullptr, &time);
        if (selectResult == -1)
        {
            Display_PError("select");
        }
        else if (selectResult > 0) // 0 means it timed-out
        {
            int receivedBytes = recvfrom(linuxSocket, buffer, 
                        recvBufferLength, 0, reinterpret_cast<sockaddr*>(&sender),
                        reinterpret_cast<socklen_t*>(&senderLen));

            if (receivedBytes == -1)
            {
                Display_PError("recvfrom");
            }
            else if (receivedBytes > 0)
            {
                Message msg;
                msg.prefix = buffer[0];
                msg.msg = string(buffer + 1, buffer + receivedBytes);
                msg.address = sender.sin_addr;
                return msg;
            }
        }
        Message m;
        m.prefix = 'N';
        return m;
    }

为什么 select()当我可以看到数据包到达时,保持回到0?此外,为什么它在Windows< - Windows场景中工作,而不是Linux - Linux或Linux - Windows?

Why does select() keep coming back with 0 when I can see packets arriving? Moreover, why does it work in the Windows<->Windows scenario, but not Linux<->Linux or Linux<->Windows?

是套接字创建/设置代码,如所请求的。计算的示例IP /广播地址为:192.168.1.3/192.168.1.255,192.168.1.5/192.168.1.255,与Windows端生成和使用的内容相匹配。

bool NetworkLinux::StartUp()
    {
        // zero addr structures
        memset(&machineAddr, 0, sizeof machineAddr);
        memset(&broadcastAddr, 0, sizeof broadcastAddr);

        // get this machine's IP and store it
        machineAddr.sin_family = AF_INET;
        machineAddr.sin_port = htons(portNumber);
        inet_pton(AF_INET, GetIP().c_str(), &(machineAddr.sin_addr));

        // get the netmask and calculate/store the correct broadcast address
        broadcastAddr.sin_family = AF_INET;
        broadcastAddr.sin_port = htons(portNumber);
        GetNetMask();
        broadcastAddr.sin_addr.s_addr = machineAddr.sin_addr.s_addr | ~netmask;

        char bufIP[INET_ADDRSTRLEN], bufBroadcast[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &machineAddr.sin_addr, bufIP, INET_ADDRSTRLEN);
        inet_ntop(AF_INET, &broadcastAddr.sin_addr, bufBroadcast,
                INET_ADDRSTRLEN);
        Log("IP is: " + string(bufIP) + "\nBroadcast address is: "
                + string(bufBroadcast));

        // create socket
        linuxSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (linuxSocket == -1)
        {
            Display_PError("socket");
            return false;
        }
        Log("Socket created.");

        // switch to broadcast mode
        int broadcast = 1;
        if (setsockopt(linuxSocket, SOL_SOCKET, SO_BROADCAST, &broadcast,
                sizeof broadcast) == -1)
        {
            Display_PError("setsockopt");
            close(linuxSocket);
            return false;
        }
        Log("Socket switched to broadcast mode.");

        // bind it (this simplifies things by making sure everyone is using the same port)
        if (bind(linuxSocket, reinterpret_cast<sockaddr*>(&machineAddr),
                sizeof(machineAddr)) == -1)
        {
            Display_PError("bind");
            close(linuxSocket);
            return false;
        }
        Log("Socket bound.");

        return true;
    }


推荐答案

machineAddr.sin_port = htons(portNumber);
inet_pton(AF_INET, GetIP().c_str(), &(machineAddr.sin_addr));

bind(linuxSocket, reinterpret_cast<sockaddr*>(&machineAddr),

绑定套接字以仅接受在 GetIP 返回的机器地址处发送到 portNumber 的数据包,这可能不是您您可能想要将 sin_addr 设置为 INADDR_ANY ,您可能希望在广播地址接收发送到端口的数据包$ c>,通配符地址,这将允许套接字接收发送到端口在任何地址,以某种方式到达机器的数据包。

This binds the socket to only accept packets sent to portNumber at the machine address returned by GetIP, which is probably not what you want, as you also want to receive packets sent to the port at the broadcast address. You probably want to set sin_addr to be INADDR_ANY, the wildcard address, which will allow the socket to receive packets sent to the port at any address that gets to the machine somehow.

这篇关于UDP广播正在发送,但未收到的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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