C# 从异步套接字接收完整数据

C# 从异步套接字接收完整数据,c#,sockets,asynchronous,networking,C#,Sockets,Asynchronous,Networking,我的这段代码(见下文)受到了 代码应该从存储在缓冲区中的客户机获取完整请求,所有这些都是在异步上下文中完成的。 请注意,下面的代码是第一次使用调用的: state.SourceSocket.BeginReceive(新的异步回调(ReceiveFromClient),state) 这里是状态类,只是为了清楚起见 public class State { public Socket SourceSocket { get; private set; } public Socket D

我的这段代码(见下文)受到了
代码应该从存储在缓冲区中的客户机获取完整请求,所有这些都是在异步上下文中完成的。 请注意,下面的代码是第一次使用调用的:
state.SourceSocket.BeginReceive(新的异步回调(ReceiveFromClient),state)

这里是
状态
类,只是为了清楚起见

public class State
{
    public Socket SourceSocket { get; private set; }
    public Socket DestinationSocket { get; private set; }

    public int BufferSize;
    public byte[] Buffer { get; private set; }
    public string bufferString;
    public StringBuilder sb = new StringBuilder();

    public State(Socket source, Socket destination, int bufferSize)
    {
        SourceSocket = source;
        DestinationSocket = destination;
        Buffer = new byte[bufferSize];
        BufferSize = bufferSize;
    }
}
问题如下:
第一次调用
ReceiveFromClient
似乎工作正常,我得到了一些数据,但当我第二次调用
BeginReceive
时,什么都没有发生,我甚至不再进入回调。

请注意,这可能是一个初学者的错误,因为这是我第一次处理c应用程序。

错误的概念是,如果
bytesRead==0
意味着套接字断开连接。所以你不能等到没有字节了。如果在一次读取中收到所有字节,则必须填充
state.bufferString=state.sb.ToString()问题是。。TCP是一种流协议,因此您需要指定完成数据包/消息的内容。大多数协议都会发送一个指定数据长度的报头
[header(data.length)][data][header(data.length)][data]
@JeroenvanLangen您需要小心该断言-IIRC您可以执行零长度异步读取,这对于执行零成本“等待有一些数据”非常有用;i、 e.“如果没有数据,进行零长度读取,当有数据时会回调,然后我可以重新评估下一步要做什么”@MarcGravel从未听说过。所以它有点像异步的
DataAvailable
。这意味着要跟踪请求检查是否断开连接的字节数。在这种情况下,我在第一次读取时有效地接收到整个请求,但这并不总是正确的。但是像这样再次调用beginRead的想法来自msdn文档本身,所以我不知道..@JeroenvanLangen yep,就是这样;当您有许多套接字需要服务,并且您不想分配大量缓冲区或必须跟踪单个共享缓冲区的大量片段时,这非常有用-您可以说“读取零字节并在完成后返回给我”。错误的概念是,如果
bytesRead==0
意味着套接字已断开连接。所以你不能等到没有字节了。如果在一次读取中收到所有字节,则必须填充
state.bufferString=state.sb.ToString()问题是。。TCP是一种流协议,因此您需要指定完成数据包/消息的内容。大多数协议都会发送一个指定数据长度的报头
[header(data.length)][data][header(data.length)][data]
@JeroenvanLangen您需要小心该断言-IIRC您可以执行零长度异步读取,这对于执行零成本“等待有一些数据”非常有用;i、 e.“如果没有数据,进行零长度读取,当有数据时会回调,然后我可以重新评估下一步要做什么”@MarcGravel从未听说过。所以它有点像异步的
DataAvailable
。这意味着要跟踪请求检查是否断开连接的字节数。在这种情况下,我在第一次读取时有效地接收到整个请求,但这并不总是正确的。但是像这样再次调用beginRead的想法来自msdn文档本身,所以我不知道..@JeroenvanLangen yep,就是这样;当您有很多套接字需要服务,并且您不想分配大量缓冲区或必须跟踪单个共享缓冲区的大量片段时,这非常有用-您可以说“读取零字节,完成后返回给我”
public class State
{
    public Socket SourceSocket { get; private set; }
    public Socket DestinationSocket { get; private set; }

    public int BufferSize;
    public byte[] Buffer { get; private set; }
    public string bufferString;
    public StringBuilder sb = new StringBuilder();

    public State(Socket source, Socket destination, int bufferSize)
    {
        SourceSocket = source;
        DestinationSocket = destination;
        Buffer = new byte[bufferSize];
        BufferSize = bufferSize;
    }
}