【问题标题】:Server do not receive all messages服务器没有收到所有消息
【发布时间】:2016-04-26 00:24:09
【问题描述】:

我有 2 台电脑:我会称它们为 Comp A、Comp B;

我必须:

  1. 将 PCM 格式的声音文件从 Comp А 发送到 Comp B;
  2. 验证此文件的传输精度;
  3. 在 Comp B 上播放我发送给 Comp B 的内容。

要发送文件,我使用函数

socket.SendTo(packet,0,count,SocketFlags.None,remoteEP);

来自System.Net.Sockets

因此,我得出结论,文件正在准确传输。我在 Comp A 和 Comp B 上使用 Wireshark 对其进行监控。但是,到达 Comp B 的字节包与正在传输的文件完全不一致。

发送文件数据的程序,以正确的方式打开这个文件。然后它将源 PCM 文件的右字节传递给函数Socket.SendTo(...)。但是 Comp A(输出)的 Wireshark 显示绝对不正确的字节,即 Comp A 发送的字节不正确。

可能是什么问题?


我发现了那个函数socket.SendTo(packet,0,count,SocketFlags.None,remoteEP); 如果我延迟发送它们,则发送正确的字节。我的意思是我可以发送 400 个字节(没有循环),我的程序发送 400 个绝对精确、正确的字节。

但是我有一个很大的 PCM 文件。它的大小约为 50 Mb。其持续时间为 1 分钟。我必须在一分钟内发送这个文件,以便这个文件被均匀、统一地传输。这意味着每秒需要传输大约 800 Kb。
所以这是我的程序代码。我使用每秒调用 2 次的定时器函数每秒发送 800 Kb。

private void m_pTimer_Tick(object sender,EventArgs e)  
{  
    uint sent_data = 0;

    while ((sent_data <= (BUFFERSIZE / 120)) && ((num * RAW_PACKET) + sent_data  < BUFFERSIZE))
    {
        uint bytes_count = ((BUFFERSIZE - (RAW_PACKET * num)) > RAW_PACKET) ? RAW_PACKET : (BUFFERSIZE - (RAW_PACKET * num));
        byte[] buffer = new byte[bytes_count];
        Array.Copy(ReadBuffer, num * RAW_PACKET, buffer, 0, bytes_count);
        num++;

        // Send and read next.
        m_pUdpServer.SendPacket(buffer, 0, Convert.ToInt32(bytes_count), m_pTargetEP);
        sent_data += bytes_count;
    }

    if ((num * RAW_PACKET) + sent_data == BUFFERSIZE)
    {
        m_pTimer.Enabled = false;
    }
    m_pPacketsReceived.Text = m_pUdpServer.PacketsReceived.ToString();
    m_pBytesReceived.Text   = m_pUdpServer.BytesReceived.ToString();
    m_pPacketsSent.Text     = m_pUdpServer.PacketsSent.ToString();
    m_pBytesSent.Text       = m_pUdpServer.BytesSent.ToString();
}

如果我在没有计时器或任何循环(while 等)的情况下调用函数 m_pUdpServer.SendPacket(buffer, 0, Convert.ToInt32(bytes_count), m_pTargetEP);,我会在输出中看到正确的结果。

这里是 120 - 在每个计时器函数调用的一段时间内传输的文件部分的数量。定时器函数每秒调用 2 次。

  • BUFFERSIZE 是总文件大小。
  • ReadBuffer 是一个包含所有 PCM 文件数据的数组。
  • RAW PACKET = 400 字节。
  • sent_data 是在每个定时器函数调用中发送的总字节数。
  • num 是发送数据包的总数。

我想在定时器函数调用中发送的数据包(字节)太多。因此,我在输出中看到不正确的值。

那么解决这个问题的方法是什么?

我想我可以组成一个 RTP 数据包(为每个发送的数据包添加一个序列号)。它将帮助我识别接收到的数据包并组成正确的接收数据包序列。如果收到的数据包具有正确的字节序列,它可以帮助我。因为如果接收到的数据包具有混合字节顺序(序列),我不明白如何在每个接收到的数据包中恢复正确的字节序列。

我被建议拒绝计时器调用并均匀发送数据包,统一使用时间同步。其实我不知道该怎么做。也许我应该使用线程、线程池或类似的东西。你怎么看?

【问题讨论】:

  • SendTo 发送的字节数可能少于count 字节,按设计
  • ....这就是为什么它返回 de sent bytes count
  • 在wireshark上看到trame时要小心字节序
  • 不,如果我交换位置字节,我看不到类似的东西
  • API 没问题。套接字准确地发送和接收您告诉它们的字节。如果您认为他们没有这样做,那么要么您将错误的字节传递给了 send 方法,要么没有正确处理您收到的字节。缺少一个好的minimal reproducible example 是不可能告诉你你做错了什么。哎呀,你甚至没有告诉我们这是 TCP 还是 UDP(SendTo() 通常表示 UDP,但许多 .wav 文件太大而无法放入单个 UDP 数据报)。

标签: c# .net sockets udp


【解决方案1】:

UDP 为您提供的唯一保证是传递整个消息。但是,如果您按顺序发送片段 1、2、3、4,它们可能会以任何顺序接收,例如 4132。也就是说,UDP 不保证排序。

您必须包含一个序列号才能正确存储 PCM。

UDP 也不保证交付。如果服务器在 X 秒内收到 #4 但没有收到 #5,它可能应该再次请求该部分。

或者您将切换到 TCP。容易得多。您所需要的只是某种方式来告诉文件的长度,然后将其传输。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-12
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多