【问题标题】:C# Asynchronous sendingC# 异步发送
【发布时间】:2009-11-11 00:38:55
【问题描述】:

我最近一直在用C#做异步发送,就在几天前,当我遇到需要发送多个位的数据时,我开始怀疑发送的数据是否按顺序发送。

所以我的问题是,当您在 C# 中异步发送数据时,它是否会在发送数据时相应地发送数据?

例如。 我发送一个包含 10 个字节的数据数组,在我发送它之后,我发送一个包含 5 个字节的数组。这是否意味着包含 5 个字节的数组将首先到达远程客户端(因为 5 个字节的处理时间很可能少于 10 个)?

这是代码(C#):

    /// <summary>
    /// Sends the welcome screen to the character.
    /// </summary>
    /// <param name="character">The character requesting the welcome screen.</param>
    public void SendWelcomeScreen(Character character)
    {
        SendWindowPane(character, 549);
        SendInterface(character, 1, 549, 2, 378);
        SendInterface(character, 1, 549, 3, 15);
        SendString(character, "Welcome to " + GameEngine.World.Name + ".", 378, 115);
        // TODO: last ip
        SendString(character, "You are connected from: " + character.Session.Connection.IPAddress, 378, 116);
        SendString(character, "0", 378, 39);
        SendString(character, "0", 378, 96);
        SendString(character, "0 unread messages", 378, 37);
        SendString(character, GameEngine.World.Name + " staff will NEVER email you. We use the Message Centre on the website instead.", 378, 38);
        SendString(character, "0 days of member credit", 378, 94);
        SendString(character, "You have 0 days of member credit remaining. Please click here to extend your credit.", 378, 93);
        SendString(character, "You do not have a bank pin. Please visit a bank if you would like one.", 378, 62);
        SendString(character, "You have not yet set any recovery questions.", 378, 56);
        SendString(character, "Message of the Week", 15, 0);
        SendString(character, "Remember to keep your account secure: set a bank PIN, set recover questions and NEVER give away your password.", 15, 4);
    }

    /// <summary>
    /// Sends a window pane to the character's client.
    /// </summary>
    /// <param name="character">The character to send window pane to.</param>
    /// <param name="pane">The pane id.</param>
    public void SendWindowPane(Character character, short pane)
    {
        character.Session.SendPacket(
            new PacketBuilder(239)
            .AppendShort(pane)
            .AppendByteA(0));
    }

    /// <summary>
    /// Sends an interface to the character's client.
    /// </summary>
    /// <param name="character">The character to send interface to.</param>
    /// <param name="showId">The show ids.</param>
    /// <param name="windowId">The window id.</param>
    /// <param name="interfaceId">The interface id.</param>
    /// <param name="childId">The child id.</param>
    public void SendInterface(Character character, byte showId, short windowId, short interfaceId, short childId)
    {
        character.Session.SendPacket(
            new PacketBuilder(93)
            .AppendShort(childId)
            .AppendByteA(showId)
            .AppendShort(windowId)
            .AppendShort(interfaceId));
    }

    /// <summary>
    /// Sends a piece of text to the character's client.
    /// </summary>
    /// <param name="character">The character to send the text to.</param>
    /// <param name="text">The string to be displayed.</param>
    /// <param name="interfaceId">The interface id of which we place this text on.</param>
    /// <param name="childId">The child id of which we place this text on.</param>
    public void SendString(Character character, string text, short interfaceId, short childId)
    {
        int stringSize = text.Length + 5;
        character.Session.SendPacket(
            new PacketBuilder(179)
            .AppendByte((byte)(stringSize / 256))
            .AppendByte((byte)(stringSize % 256))
            .AppendString(text)
            .AppendShort(childId)
            .AppendShort(interfaceId));
    }

【问题讨论】:

  • “发送”用什么方式?举个例子怎么样?
  • 简短回答:这取决于。我们可能需要看一些代码才能更具体地回答。
  • 好的,我已经添加了一些代码,请看一下:)
  • 你可能在使用 WCF 吗?
  • 我很确定这没有必要成为社区维基。只是一个想法。

标签: c# networking asynchronous


【解决方案1】:

保证数据按照发布到套接字的顺序发送。换句话说,您调用NetworkStream.BeginWriteSocket.BeginSend 的顺序。最终重要的是框架为您调用WSASend 的顺序(或由CLR 完成的等效套接字写入,我不确定他们是否不使用WSAIoctl 甚至FileWriteEx,因为它们都可以工作)。来自 MSDN:

可以调用完成例程 以任何顺序,不一定在 重叠操作的顺序相同 完成。但是,发布的 缓冲区保证被发送 它们指定的顺序相同

如果您使用 I/O 完成端口, 请注意拨打电话的顺序 到 WSASend 也是其中的顺序 缓冲区已填充。发送 不应同时调用 同时从不同的socket 线程,因为它可能导致 不可预知的缓冲顺序。

因此,无论是在单个 WSASend 调用的分散/聚集缓冲区顺序内还是跨多个 WSASend 调用,都可以保证顺序。多线程调用 WSASend 问题很明显,所以我希望您的代码不是这种情况。

但是,如果您使用WSARecvSocket.BeginReceiveNetworkStream.BeginRead 将多个缓冲区发布到套接字,那么接收端的应用程序通常会出现问题,这是很容易发现自己处理它们的顺序不正确。确保您不是这种情况。

【讨论】:

  • 顺便说一句,这显然是指 TCP,您的示例不清楚,因为它实际上错过了重要的调用,例如实际的 SEND。使用 UDP,不仅不能保证顺序,实际上也不太可能发生。
  • 请注意 Remus 最后一段关于接收端通常出现故障的内容。这是要理解的重要部分。一个原因是,您和目的地之间可能的网络路由越多,意味着任何两个数据包最终采用不同路由的可能性就越大。不过,还有许多其他因素在起作用。我只是举个例子。
  • 我还假设您正在相互独立地发送数据。如果您按照其他答案中所述正确包装数据,某些协议会为您解决此问题。
  • 谢谢大家,真的很有帮助。我真的不知道在 google/bing 上搜索什么,所以我来寻求具体帮助再次感谢 :)
【解决方案2】:

这不取决于它是异步还是同步。它取决于下面的通道:如果是 TCP,则遵守订单。不保证在 UDP 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2013-01-06
    • 1970-01-01
    • 2019-11-30
    • 2011-06-26
    • 2011-04-05
    相关资源
    最近更新 更多