首先UDP消息发送给指定的远程IP丢失(First UDP message to a specifi

2019-06-26 18:13发布

我上有控制一批“运动员”“服务器”基于LAN解决方案时我选择的协议是UDP,因为它很容易,我不需要连接,我的流量仅包括简短的命令不时我想用广播消息的混合为球员个人的命令同步和单一目标的消息。

组播TCP将是一个选择,但它比较复杂,并不完全适合的任务,往往不能很好的硬件支持。

不幸的是我遇到了一个奇怪的问题:

这是使用“的sendto”发送到特定IP的第一个数据报丢失。 发送短的时间后,以相同的IP数据报的任何接收。 但是,如果我等待一段时间(几分钟)第一“的sendto”再次丢失。

广播数据包总是工作。 本地发送(在同一台计算机)总是工作。

我相信操作系统或路由器/交换机具有从IP到MAC地址的一些转换表时,不被用于一些分,不幸的是会导致丢失数据包,其被遗忘。 我所观察到不同的交换机/路由器硬件的行为,所以我怀疑是网络层中的窗口。

我知道,UDP是定义“不可靠”,但我不能相信这个去到目前为止,即使物理连接是否正常工作,一切都被很好地定义数据包可能会丢失。 然后,它会从字面上不值钱。

从技术上讲,我打开一个UDP套接字,将其绑定到一个端口和INADRR_ANY。 然后,我使用“的sendto”和“recvfrom的”。 我永远不会做一个连接 - 我不想因为我有几个球员。 据我所知UDP应该没有连接。

我目前的解决办法是,我经常发送无效数据报给所有特定玩家的IPS - 解决该问题,但其有点“不满意”

问:是否有人知道这个问题? 它从何而来? 我该如何解决呢?

编辑:

我煮下来到下面的测试程序:

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    SOCKADDR_IN Local = {0};
    Local.sin_family = AF_INET;
    Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    Local.sin_port = htons(1234);
    bind(Sock, (SOCKADDR*)&Local, sizeof(Local));
    printf("Press any key to send...\n");
    int Ret, i = 0;
    char Buf[4096];

    SOCKADDR_IN Remote = {0};
    Remote.sin_family = AF_INET;
    Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12");  // Replace this with a valid LAN IP which is not the hosts one
    Remote.sin_port = htons(1235);

    while(true) {
        _getch();
        sprintf(Buf, "ping %d", ++i);
        printf("Multiple sending \"%s\"\n", Buf);

        // Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote));
        // if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        }
    return 0;

该程序打开一个UDP套接字,并在每次击键到特定IP连续发送3个数据报。 运行蒙山Wireshark的观察你的UDP流量,按一个键,稍等片刻,再按下一个键。 你并不需要一个接收器上的远程IP,没有什么区别,除了你不会得到黑色标记为“不可达”的数据包。 这是你会得到什么:

正如你所看到的第一个发送发起的ARP搜索的IP。 而该搜索被挂起的3连续的第一2发送丢失了。 第二个按键(后IP搜索是完全的)正确发送3个消息。 现在,您可以重复发送消息,它会工作,直到你等待(约一分钟,直到ADRESS翻译被再度迷失),那么你将再次看到辍学。

这意味着:没有发送UDP消息时发送缓冲区,但存在未处理的ARP请求! 所有消息迷路除了最后一个。 还“的sendto”不会阻止,直到成功交付,并没有错误回报!

嗯,这让我惊讶,让我有点难过,因为这意味着我不得不住在一起,我目前的解决方法或实现一个ACK系统一次只能发送一个消息,然后等待回复 - 这是不容易的任何越来越意味着许多困难。

Answer 1:

它已经被别人回答后,我长张贴本,但它直接关系。

Winsock的下降UDP数据包是否有对应的目标地址(或目的地的网关)没有ARP表项。

因此,它很可能一些第一UDP数据包被丢弃成为了当时没有ARP表项 - 而不像大多数其他操作系统,winsock的同时ARP请求仅完成队列1包。

这是记录在这里 :

ARP队列只有一个为指定的目的地址的出站IP数据报,而该IP地址已经被解析为MAC地址。 如果一个基于UDP的应用程序将多个IP数据报以一个单一的目的地址,它们之间没有停顿,一些数据报可如果没有ARP缓存项已经存在的下降。 应用程序可以通过调用IPHLPAPI.DLL常规SendArp()来建立一个ARP缓存项,发送数据包的流之前弥补这一点。

可以观察到同样的行为的Mac OS X和FreeBSD的 :

当接口在缓存请求映射的地址不,ARP队列这就需要映射和广播相关的相关的网络请求的地址映射在消息的消息。 如果提供了响应,新的映射被高速缓存和任何未决消息被发送。 ARP将排队至多一个分组在等待映射请求的响应; 仅最近``“发送”包被保留。



Answer 2:

UDP数据包应该在接收到被缓冲,但是UDP分组(或以太网帧保持它)可在给定机器上的几个点被丢弃:

  1. 网络卡没有足够的空间来接受它,
  2. OS网络堆栈没有足够的缓冲存储器复制到,
  3. 防火墙/包过滤下拉式规则匹配,
  4. 没有应用程序正在侦听目标IP和端口,
  5. 收到监听应用插座缓冲区已满。

前两点是关于流量太大,这是不太可能的情况下在这里。 然后,我相信这一点4.不适用,您的软件正在等待数据。 第5点是关于你的应用程序不处理网络数据足够快的速度 - 也似乎不是如此。

MAC和IP地址之间的转换是通过进行地址解析协议 。 这不会导致数据包丢弃,如果你的网络配置正确。

我将禁用Windows防火墙和任何防病毒/深度包检测软件和检查什么是与电线Wireshark的 。 这很可能会指向你到正确的方向 - 如果你能嗅出那些第一包的“发送到”机器然后检查本地配置(防火墙等); 如果你不这样做,那么请检查您的网络 - 这是在路径与您的交通干扰。

希望这可以帮助。



Answer 3:

呃.....它的计算机做ARP请求。 当你第一次开始发送,你的COM不知道接收机的MAC地址,因此它无法发送任何数据包。 它使用接收器做一个ARP请求来获取MAC地址的IP地址。 在此过程中,您尝试发送任何UDP数据包不能被发送出去的目的MAC地址仍不得而知。

一旦你的COM接收MAC地址可以开始发送。 然而,MAC地址将只能停留在你的COM的ARP缓存为2分钟或10分钟(如果你和接收器之间没有检测到进一步的活动)(全透明的ARP缓存中,即使连接处于活动状态)。 这就是为什么你遇到此问题,每隔几分钟。



Answer 4:

是否有人知道这个问题?

真正的问题是,你认为UDP报文的发送是可靠的。 事实并非如此。

你失去了第一个数据包与当前的网络配置的事实确实是一个次要问题。 你也许能够解决这个问题,但在任何时候,你仍然容易受到数据包丢失。

如果丢包是你有问题,那么你真的应该使用TCP。 你可以建立在UDP可靠的协议,但除非你有一个很好的理由这样做,它没有建议。



文章来源: First UDP message to a specific remote ip gets lost