发送至特定远程 IP 的第一个 UDP 消息丢失

2023-11-24

我正在开发一个基于 LAN 的解决方案,其中一个“服务器”必须控制多个“玩家” 我选择的协议是 UDP,因为它很简单,我不需要连接,我的流量仅由时不时的短命令组成,我想使用混合广播消息进行同步,并使用单个目标消息进行玩家单独的命令。

多播 TCP 是一种替代方案,但它更复杂,不完全适合该任务,并且通常得不到硬件的良好支持。

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

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

广播数据报始终有效。 本地发送(到同一台计算机)始终有效。

我推测操作系统或路由器/交换机有一些从 IP 到 MAC 地址的转换表,在几分钟不使用时会被遗忘,不幸的是会导致数据报丢失。 我可以用不同的路由器/交换机硬件观察到这种行为,所以我怀疑是 Windows 网络层。

我知道 UDP 根据定义是“不可靠的”,但我无法相信这种情况会发展到即使物理连接正常工作并且一切都定义良好的数据包也可能丢失。那么它就真的毫无价值了。

从技术上讲,我正在打开一个 UDP 套接字, 将其绑定到端口和 INADRR_ANY。 然后我使用“sendto”和“recvfrom”。 我从不进行连接——我不想这样做,因为我有几个玩家。据我所知,UDP 应该在没有连接的情况下工作。

我当前的解决方法是定期向所有特定玩家 ip 发送虚拟数据报 - 这解决了问题,但在某种程度上“不令人满意”

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

Edit:

我将其归结为以下测试程序:

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 套接字,并在每次击键时连续发送 3 个数据报到特定 IP。 运行whithwireshark观察你的UDP流量,按下一个键,等待一段时间,然后再次按下一个键。 您不需要远程 IP 上的接收器,这没有什么区别,除非您不会收到黑色标记的“无法到达”数据包。 这就是你得到的:

Wireshark Snapshot

正如您所看到的,第一次发送启动了 IP 的 ARP 搜索。当搜索等待时,连续 3 次发送中的前 2 次丢失。 第二次击键(IP 搜索完成后)正确发送了 3 条消息。 您现在可以重复发送消息,它会一直工作,直到您等待(大约一分钟,直到地址翻译再次丢失),然后您将再次看到丢失。

这意味着:发送 UDP 消息时没有发送缓冲区,并且有 ARP 请求待处理!除最后一条消息外,所有消息都会丢失。 另外“sendto”在发送成功之前不会阻塞,并且不会有错误返回!

好吧,这让我感到惊讶,也让我有点难过,因为这意味着我必须接受当前的解决方法,或者实现一个 ACK​​ 系统,一次只发送一条消息,然后等待回复 - 这对任何人来说都不容易更多,意味着许多困难。


我在其他人回答之后很久才发布这个帖子,但它是直接相关的。

如果没有目标地址(或目标网关)的 ARP 条目,Winsock 将丢弃 UDP 数据包。

因此,很可能第一个 UDP 数据包的某些数据包会被丢弃,因为此时没有 ARP 条目 - 并且与大多数其他操作系统不同,winsock 在 ARP 请求完成时仅排队 1 个数据包。

这是有记录的here:

ARP 仅对指定目的地的一个出站 IP 数据报进行排队 地址,同时将该 IP 地址解析为 MAC 地址。如果一个 基于 UDP 的应用程序将多个 IP 数据报发送到单个 目标地址之间没有任何停顿,一些 如果还没有 ARP 缓存条目,数据报可能会被丢弃 展示。应用程序可以通过调用来补偿这一点 Iphlpapi.dll例程SendArp()建立一个ARP缓存条目,之前 发送数据包流。

可以在以下位置观察到相同的行为Mac OS X and FreeBSD:

当接口请求地址映射时, 在缓存中,ARP 将需要的消息排队 映射并在关联的关联上广播消息 网络请求地址映射。如果响应是 如果新的映射被缓存并且任何待处理的消息被缓存 传送。 ARP 在等待时最多排队一个数据包 用于响应映射请求;仅最近的 保留“已传输”数据包。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

发送至特定远程 IP 的第一个 UDP 消息丢失 的相关文章

随机推荐

  • 似乎正在等待的线程的 CPU 利用率很高

    我目前正在运行一些 JMeter 测试来测试 Web 服务的性能 它使用了大量的 CPU 对于一个 JMeter 请求线程 其使用率为 10 30 取决于请求的类型 当我将其增加到仅 15 个线程时 CPU 利用率约为 95 自然 我想弄清
  • 演示正在进行时在场吗?尝试在 facebook 登录后使用解析显示新视图。

    我试图呈现一个我已经为用户输入数据并保存在解析中的 UITableView 我很确定我没有呈现导航视图 当我登录时 我收到错误 Checklists 4516 c07 Warning Attempt to present
  • Android SQLite 在复杂查询中的性能

    假设我有这样的查询 String sql SELECT s team id s team name s gp s w s t s l s go s ga s score s p FROM SELECT team id team name S
  • Google Maps API V3 - 无论如何要检索自动完成结果而不是下拉渲染吗?

    我需要渲染结果google maps places Autocomplete以自定义方式 而不是默认的下拉菜单 有什么方法可以使用 Google Maps API V3 检索自动完成的相同信息 但在每个请求的数组中而不是 API 为我进行渲
  • 检查本地存储是否可用

    我知道有很多关于检查的问题localStorage但如果有人在浏览器中手动关闭它怎么办 这是我用来检查的代码 localStorage setItem mod mod if localStorage getItem mod null ale
  • 活动被销毁是因为方向改变还是因为应用程序正在关闭?

    我有一个Activity启动一个异步任务 允许以纵向或横向方向显示活动 当方向改变时 Activity 将被销毁并重新创建 无论方向改变多少次 任务都会继续工作 它还成功地将结果返回给活动 根据 CommonsWare 的回答 http g
  • 如何使用 Selenium WebDriver C# 从下拉列表中选择一个选项?

    我正在尝试选择一个选项进行网络测试 可以在这里找到一个例子 http www tizag com phpT examples formex php 除了选择一个选项部分之外 一切都很好 如何按值或按标签选择选项 My Code using
  • 如何将 selenium chrome 选项添加到“desiredCapability”?

    对于 selenium 我有很多 chrome 选项 我需要通过以下方式将其传递给远程网络驱动程序DesiredCapabilities 在本页有一个关于如何执行此操作的 java 示例 但是如何在 python 中执行此操作 这文档很穷
  • 使用 CNN 处理一维数据

    只是想知道是否有人这样做过 我有一个一维的数据集 但不确定它是否是正确的单词选择 与通常的 CNN 输入图像 二维 不同 我的数据只有一维 一个例子是 instance1 feature1 feature2 featureN instanc
  • Python ctypes 未在 Mac OS X 上加载动态库

    我有一个 C 库repeater so我可以通过以下方式从 Linux 中的 Python 加载 import numpy as np repeater np ctypeslib load library librepeater so 但是
  • 使用 GCC 的链接器错误,包括。用于 binutils 和 textinfo

    我每次在编译程序 配置和安装一些东西时都会收到此错误 例如binutils 文本信息等 usr local bin ld this linker was not configured to use sysroots collect2 err
  • 使用 Apple Pay 创建令牌,无需付款

    我有两个问题 有没有办法使用 Apple Pay 创建 STPToken 而无需付款 在我的 iOS 应用程序中 客户在注册时要么输入付款信息 要么决定使用 Apple Pay 当客户决定购买时 注册后的某个时间 他们的卡将自动扣款 我可以
  • Kdevelop 步骤和断点不起作用

    我需要使用步骤 单步执行 单步执行指令 和断点 但选项 跳过 跳过指令 等 在菜单 运行 中被禁用 当我在程序中放置断点时 程序不会在此断点处停止 我发现我必须关闭编译器和链接器的优化 但我不知道如何关闭 Kdevelop 4 4 1 中的
  • ASP.NET:视图状态和以编程方式添加用户控件

    当使用 LoadControl string path 以编程方式添加用户控件时 在用户控件的页面生命周期中 它何时使用其视图状态初始化其子控件 我问这个问题是因为我正在以编程方式加载的用户控件之一有一个 TextBox 控件 该控件未通过
  • 使用批处理文件命名驱动器

    我正在寻找一个命令来重命名我在 WinXP 中每次启动时映射的几个驱动器 我已经完成了映射部分 现在我有兴趣使用自定义名称以编程方式命名它们 这样我就可以保持它们的一致性 我放弃了 DOS 转而学习 PowerShell 最终的结果是这样的
  • Node.js“require”语句中的大括号(大括号)

    我试图理解下面两个 require 语句之间的区别 具体来说 其目的是什么 s 缠绕着ipcMain const electron require electron const ipcMain require electron 他们似乎都分
  • 如何在 Android 中缩放文本视图?

    谁能指导我在android中的多个视图上执行放大和缩小操作 我需要在图像 文本视图的触摸上执行放大和缩小操作 我的父级布局应该是什么 这是在触摸图像视图时缩放图像的代码 如何缩放文本视图 请帮我 These matrices will be
  • 所有 OLE 错误代码的列表

    是否有所有 OLE 错误代码的列表 None
  • 如何跟踪 WCF 序列化问题/异常

    我偶尔会遇到这样的问题 在 WCF 序列化期间 从我的 OperationContract 返回 DataContract 后 抛出应用程序异常 我收到的唯一 且意义不大 的消息是 System ServiceModel Communica
  • 发送至特定远程 IP 的第一个 UDP 消息丢失

    我正在开发一个基于 LAN 的解决方案 其中一个 服务器 必须控制多个 玩家 我选择的协议是 UDP 因为它很简单 我不需要连接 我的流量仅由时不时的短命令组成 我想使用混合广播消息进行同步 并使用单个目标消息进行玩家单独的命令 多播 TC