相当于 C# 异步套接字中的 Peek?

Posted

技术标签:

【中文标题】相当于 C# 异步套接字中的 Peek?【英文标题】:Equivalent of Peek in C# async sockets? 【发布时间】:2011-05-06 02:42:00 【问题描述】:

我习惯使用同步套接字。为了处理尚未完全到达的消息,我将前 4 个字节设置为消息的预期长度。然后我会使用Socket.Receive(tcpRecv, 1024, SocketFlags.Peek); 来查看消息而不将其从缓冲区中拉出。如果所有这些都在那里,我会提取数据。如果不是,我会把它留在那里。我设计了我的协议,使任何消息都不会超过 1024 字节。

在异步套接字中,我看不到查看数据的方法。有没有办法做到这一点?有没有比查看数据更好的方法?

谢谢。

-尼克

【问题讨论】:

【参考方案1】:

您无需窥视:.NET 异步套接字允许您实现相同类型的功能而无需窥视。我想你可能正在寻找这样的东西:

private void BeginReceive()

    if ( _clientState == EClientState.Receiving)
    
        if (_asyncTask.BytesReceived != 0 && _asyncTask.TotalBytesReceived <= _maxPageSize)
        
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.SetBuffer(_asyncTask.ReceiveBuffer, 0, _asyncTask.ReceiveBuffer.Length);
            e.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCallback);
            e.UserToken = _asyncTask.Host;

            bool comletedAsync = false;
            try
            
                comletedAsync = _socket.ReceiveAsync(e);
            
            catch (SocketException se)
            
                Console.WriteLine("Error receiving data from: " + _asyncTask.Host);
                Console.WriteLine("SocketException: 0 Error Code: 1", se.Message, se.NativeErrorCode);

                ChangeState(EClientState.Failed);
            

            if (!comletedAsync)
            
                // The call completed synchronously so invoke the callback ourselves
                ReceiveCallback(this, e);
            
        
        else
        
            //Console.WriteLine("Num bytes received: " + _asyncTask.TotalBytesReceived);
            ChangeState(EClientState.ReceiveDone);
        
    

当您收到回调时,您可以安排另一个接收:

private void ReceiveCallback(object sender, SocketAsyncEventArgs args)

    lock (_sync) // re-entrant lock
    
        // Fast fail: should not be receiving data if the client
        // is not in a receiving state.
        if (_clientState == EClientState.Receiving)
        
            String host = (String)args.UserToken;

            if (_asyncTask.Host == host && args.SocketError == SocketError.Success)
            
                try
                
                    Encoding encoding = Encoding.ASCII;
                    _asyncTask.BytesReceived = args.BytesTransferred;
                    _asyncTask.TotalBytesReceived += _asyncTask.BytesReceived;
                    _asyncTask.DocSource += encoding.GetString(_asyncTask.ReceiveBuffer, 0, _asyncTask.BytesReceived);

                    BeginReceive();
                
                catch (SocketException e)
                
                    Console.WriteLine("Error receiving data from: " + host);
                    Console.WriteLine("SocketException: 0 Error Code: 1", e.Message, e.NativeErrorCode);

                    ChangeState(EClientState.Failed);
                
            
            else if (_asyncTask.Host != host)
            
                Console.WriteLine("Warning: received a callback for 0, but the client is currently working on 1.",
                    host, _asyncTask.Host);
            
            else
            
                Console.WriteLine("Socket Error: 0 when receiving from 1",
                   args.SocketError,
                   _asyncTask.Host);
                ChangeState(EClientState.Failed);
            
        
    

你可以在我的博客上看到整个异步客户端:http://codesprout.blogspot.com/2011/04/asynchronous-http-client.html

【讨论】:

【参考方案2】:

您的相同数据流无需窥视即可工作:

安排四字节读取 完成后,将其保存在缓冲区中并解码为长度“n” 安排读取长度为“n” - 4 完成后,将其附加到已经存在的四个字节 解码您的消息

与偷看的唯一区别是,你必须在最初读取它们时保存四个字节。

【讨论】:

请记住,您必须处理部分读取完成,因此代码实际上变得相当复杂。我有一个类on my blog,它实现了一个4字节长度的前缀。 @Stephen Cleary:是的,大概他对旧代码也有同样的问题,而且伯克利套接字也进行部分读取。 “你并不总能得到你想要的,但如果你有时尝试,......”

以上是关于相当于 C# 异步套接字中的 Peek?的主要内容,如果未能解决你的问题,请参考以下文章

C# 异步套接字概念

如何在 C# 应用程序中取消异步发送套接字

在 C++ 中通过 'recv' 和 'MSG_PEEK' 获取套接字中可用的字节数

C#异步套接字服务器没有收到来自Java客户端的响应

在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率

UWP C#异步套接字服务器不能接受