简体   繁体   English

C#异步发送

[英]C# Asynchronous sending

I've been working with asynchronous sending in C# lately, and just a couple of days ago when I encountered that I needed to send multiple bits of data, i started wondering if the data sent are sent in order. 我最近一直在使用C#进行异步发送,而就在几天前,当我遇到需要发送多个数据位时,我开始怀疑发送的数据是否按顺序发送。

So my question is, when you send data asynchronously in C#, does it send the data accordingly as it's sent? 所以我的问题是,当您使用C#异步发送数据时,它是否在发送数据时也相应地发送数据?

Eg. 例如。 I send an array of data holding 10 bytes, and right after I send it, I send an array holding 5 bytes. 我发送一个包含10个字节的数据数组,发送后立即发送一个包含5个字节的数组。 Would this mean that the array holding 5 bytes would reach the remote client first (seeing as 5 bytes would most likely take less time to process than 10)? 这是否意味着包含5个字节的数组将首先到达远程客户端(看来5个字节最有可能花费的时间少于10个)?

Here's the code (C#): 这是代码(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));
    }

The data is guaranteed to be sent in the order posted to the socket. 保证按发布到套接字的顺序发送数据。 In other words the order in which you call NetworkStream.BeginWrite or Socket.BeginSend . 换句话说,您调用NetworkStream.BeginWriteSocket.BeginSend的顺序 Ultimately what matters is the order in which WSASend is called by the framework for you (or the equivalent socket write done by CLR, I'm not sure if they not use WSAIoctl or even FileWriteEx , since they all work). 最终,最重要的是框架为您调用WSASend的顺序(或CLR完成的等效套接字写操作,我不确定它们是否不使用WSAIoctl甚至FileWriteEx ,因为它们都可以工作)。 From MSDN: 从MSDN:

The completion routines can be called in any order, not necessarily in the same order the overlapped operations are completed. 可以以任何顺序调用完成例程,而不必以相同的顺序调用重叠操作。 However, the posted buffers are guaranteed to be sent in the same order they are specified . 但是, 保证发布的缓冲区以指定的相同顺序发送

If you are using I/O completion ports, be aware that the order of calls made to WSASend is also the order in which the buffers are populated . 如果使用的是I / O完成端口,请注意, 对WSASend的调用顺序也就是填充缓冲区的顺序 WSASend should not be called on the same socket simultaneously from different threads, because it can result in an unpredictable buffer order. 不应同时从不同的线程在同一套接字上调用WSASend,因为它可能导致不可预测的缓冲区顺序。

So the order is guaranteed both within the scatter/gather buffer order of a single WSASend call and across multiple WSASend calls. 因此,在单个WSASend调用的分散/聚集缓冲区顺序内以及在多个WSASend调用之间的顺序都得到保证。 The multiple thread invoking WSASend issue is obvious, so I hope is not the case with your code. 调用WSASend的多线程问题很明显,所以我希望您的代码不是这种情况。

However usually things get out of order in the application on the receive side if you post multiple buffers to the socket with WSARecv or Socket.BeginReceive or NetworkStream.BeginRead , it is very easy to find yourself processing them out of order. 但是,如果您使用WSARecvSocket.BeginReceiveNetworkStream.BeginRead将多个缓冲区发布到套接字,则通常在接收方的应用程序中事情会混乱容易发现自己乱序处理它们。 Make sure this is not the case for you. 确保您不是这种情况。

That doesn't depend on whether it is async or sync. 这不取决于它是异步还是同步。 It depends on channel below: if TCP, order is honored. 它取决于下面的通道:如果使用TCP,则可以接受订单。 In UDP is not guaranteed. 在UDP中不能保证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM