ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c-正在发送但未收到UDP广播

2019-11-02 06:51:11  阅读:237  来源: 互联网

标签:network-programming udp linux c-4


我正在开发一个非常简单的游戏大厅系统.每个客户端定期地通过UDP广播两个数据包,以最初发现其他客户端并传输用户信息,准备情况等.该游戏正在针对WindowsLinux(32和64位)开发.

在Windows方面,我已经使大厅系统运行正常.当我在一台Windows计算机上进入大厅时,此人在另一台计算机上弹出.同样,可以立即检测到就绪检查和断开连接.换句话说,它有效.

现在的问题是:Linux.网络代码实际上是相同的,只需要进行一些必要的特定于平台的更改.我首先尝试了Windows<> Linux.使用Wireshark,我发现Linux端确实在广播数据包并从Windows盒子接收它们,但是游戏从未捕获到数据包.我在我的select语句中发现了一个错误(套接字而不是套接字1),但是修复它并没有帮助. Windows盒正在广播数据包,但它根本没有从Linux盒接收数据包!

然后,我尝试了Linux -Linux,但是发现即使两台计算机都在广播和接收(再次通过Wireshark确认),两台计算机上的游戏也无法“看到”数据包.

我很确定这不是防火墙问题(在任何一个平台上都关闭,测试,重新打开,没有任何更改),并且网络连接似乎还可以(可以手动ping每个主机).我还检查以确保端口确实可用(它们确实存在).

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

    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中却不起作用?

编辑:这是套接字创建/设置代码,根据要求.计算出的示例IP /广播地址为:192.168.1.3/192.168.1.255、192.168.1.5/192.168.1.255,它们与Windows端生成和使用的IP地址匹配.

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,通配符地址,这将允许套接字在以某种方式到达计算机的任何地址处接收发送到端口的数据包.

标签:network-programming,udp,linux,c-4
来源: https://codeday.me/bug/20191102/1989479.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有