C# Begin/EndReceive - 如何读取大数据? [英] C# Begin/EndReceive - how do I read large data?

查看:26
本文介绍了C# Begin/EndReceive - 如何读取大数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当以 1024 的块读取数据时,如何继续从接收大于 1024 字节的消息的套接字中读取,直到没有数据为止?我应该只使用 BeginReceive 来读取数据包的长度前缀,然后一旦检索到,使用 Receive()(在异步线程中)读取数据包的其余部分?或者有其他方法吗?

When reading data in chunks of say, 1024, how do I continue to read from a socket that receives a message bigger than 1024 bytes until there is no data left? Should I just use BeginReceive to read a packet's length prefix only, and then once that is retrieved, use Receive() (in the async thread) to read the rest of the packet? Or is there another way?

我认为 Jon Skeet 的链接提供了解决方案,但该代码存在一些障碍.我使用的代码是:

I thought Jon Skeet's link had the solution, but there is a bit of a speedbump with that code. The code I used is:

public class StateObject
{
    public Socket workSocket = null;
    public const int BUFFER_SIZE = 1024;
    public byte[] buffer = new byte[BUFFER_SIZE];
    public StringBuilder sb = new StringBuilder();
}

public static void Read_Callback(IAsyncResult ar)
{
    StateObject so = (StateObject) ar.AsyncState;
    Socket s = so.workSocket;
    
    int read = s.EndReceive(ar);
    
    if (read > 0) 
    {
        so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));

        if (read == StateObject.BUFFER_SIZE)
        {
            s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0, 
                    new AyncCallback(Async_Send_Receive.Read_Callback), so);
            return;
        }
    }
    
    if (so.sb.Length > 0)
    {
        //All of the data has been read, so displays it to the console
        string strContent;
        strContent = so.sb.ToString();
        Console.WriteLine(String.Format("Read {0} byte from socket" + 
        "data = {1} ", strContent.Length, strContent));
    }
    s.Close();
}

现在这个更正大部分时间都可以正常工作,但是当数据包的大小是缓冲区的倍数时它会失败.原因是如果缓冲区在读取时被填满,则假定有更多数据;但是和以前一样发生了同样的问题.例如,一个 2 字节的缓冲区在一个 4 字节的数据包上被填充两次,并假设有更多的数据.然后它会阻塞,因为没有任何东西可以读取.问题是接收函数不知道数据包何时结束.

Now this corrected works fine most of the time, but it fails when the packet's size is a multiple of the buffer. The reason for this is if the buffer gets filled on a read it is assumed there is more data; but the same problem happens as before. A 2 byte buffer, for exmaple, gets filled twice on a 4 byte packet, and assumes there is more data. It then blocks because there is nothing left to read. The problem is that the receive function doesn't know when the end of the packet is.

这让我想到了两种可能的解决方案:我可以使用数据包结束分隔符,或者我可以读取数据包标头以找到长度,然后准确接收该数量(正如我最初建议的那样).

This got me thinking to two possible solutions: I could either have an end-of-packet delimiter or I could read the packet header to find the length and then receive exactly that amount (as I originally suggested).

不过,这些都存在问题.我不喜欢使用分隔符的想法,因为用户可以以某种方式将它放入应用程序输入字符串中的数据包中并将其搞砸.对我来说,它也似乎有点草率.

There's problems with each of these, though. I don't like the idea of using a delimiter, as a user could somehow work that into a packet in an input string from the app and screw it up. It also just seems kinda sloppy to me.

长度标头听起来不错,但我计划使用协议缓冲区 - 我不知道数据的格式.有长度标题吗?它是多少字节?这会是我自己实现的东西吗?等等.

The length header sounds ok, but I'm planning on using protocol buffers - I don't know the format of the data. Is there a length header? How many bytes is it? Would this be something I implement myself? Etc..

我该怎么办?

推荐答案

No - 从回调处理程序中再次调用 BeginReceive,直到 EndReceive 返回 0.基本上,你应该继续异步接收,假设您想要异步 IO 的最大好处.

No - call BeginReceive again from the callback handler, until EndReceive returns 0. Basically, you should keep on receiving asynchronously, assuming you want the fullest benefit of asynchronous IO.

如果您查看 MSDN 页面的 Socket.BeginReceive 你会看到一个例子.(诚​​然,它并不像想象的那么容易.)

If you look at the MSDN page for Socket.BeginReceive you'll see an example of this. (Admittedly it's not as easy to follow as it might be.)

这篇关于C# Begin/EndReceive - 如何读取大数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆