C# 套接字接收异步

Posted

技术标签:

【中文标题】C# 套接字接收异步【英文标题】:C# Socket ReceiveAsync 【发布时间】:2015-08-24 07:40:45 【问题描述】:

我习惯于同步套接字,并且为了达到现在的状态有些头疼,尤其是 Socket.Receive(..) 并不总是接收所有字节

这是我以前使用的代码

    public byte[] Receive(int size)
    
        var buffer = new byte[size];
        var r = 0;
        do
        
            // ReSharper disable once InconsistentlySynchronizedField
            var c = _clientSocket.Receive(buffer, r, size - r, SocketFlags.None);
            if (c == 0)
            
                throw new SocketExtendedException();
            
            r += c;
         while (r != buffer.Length);
        return buffer;
    

现在我开始在 Windows Phone 中使用套接字,但 .Receive(..) 不可用,我设法让 Socket.ReceiveAsync(..) 工作,但我担心(到目前为止没有发生问题)这是我的新代码,我还没有实现检查是否已收到所有字节,也不知道是否必须使用以下代码

    private byte[] ReadBySize(int size = 4)
    
        var readEvent = new AutoResetEvent(false);
        var buffer = new byte[size];
        var recieveArgs = new SocketAsyncEventArgs()
        
            UserToken = readEvent
        ;
        recieveArgs.SetBuffer(buffer, 0, size);
        recieveArgs.Completed += recieveArgs_Completed;
        _connecter.ReceiveAsync(recieveArgs);
        readEvent.WaitOne();

        if (recieveArgs.BytesTransferred == 0)
        
            if (recieveArgs.SocketError != SocketError.Success)
                throw new SocketException((int)recieveArgs.SocketError);
            throw new CommunicationException();
        
        return buffer;
    

    void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
    
        var are = (AutoResetEvent)e.UserToken;
        are.Set();
    

这是我第一次使用ReceiveAsync 有人可以指出我可能做错了什么或需要更改

【问题讨论】:

我建议使用BeginReceive() 在 windows Phone BeginRecieve 和 Recieve 不可用,我也使用 BeginReceive 但它不可用,我只能使用 StreamSocket 或 Socket (with RecieveAsync) 是的,对不起,我的错,没有读到它是 windows phone。 你在使用 TCP 吗?如果是这种情况,您是否考虑过使用TcpClient/TcpListenerNetworkStream 更容易使用。 很遗憾 TcpClient 在 Windows Phone 中也不可用 【参考方案1】:

好吧,我去拿了一个大缓冲区并分批发送它,中间有一个睡眠间隔来复制“不是所有接收到的字节”所以我上面的代码没有接收到所有字节。对于那些也使用 ReceiveAsync(..) 的人来说,这里是我的有效代码

    private byte[] ReadBySize(int size = 4)
    
        var readEvent = new AutoResetEvent(false);
        var buffer = new byte[size]; //Receive buffer
        var totalRecieved = 0;
        do
        
            var recieveArgs = new SocketAsyncEventArgs()
            
                UserToken = readEvent
            ;
            recieveArgs.SetBuffer(buffer, totalRecieved, size - totalRecieved);//Receive bytes from x to total - x, x is the number of bytes already recieved
            recieveArgs.Completed += recieveArgs_Completed;
            _connecter.ReceiveAsync(recieveArgs);
            readEvent.WaitOne();//Wait for recieve

            if (recieveArgs.BytesTransferred == 0)//If now bytes are recieved then there is an error
            
                if (recieveArgs.SocketError != SocketError.Success)
                    throw new ReadException(ReadExceptionCode.UnexpectedDisconnect,"Unexpected Disconnect");
                throw new ReadException(ReadExceptionCode.DisconnectGracefully);
            
            totalRecieved += recieveArgs.BytesTransferred;

         while (totalRecieved != size);//Check if all bytes has been received
        return buffer;
    

    void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
    
        var are = (AutoResetEvent)e.UserToken;
        are.Set();
    

我使用 Socket 应用程序的方式是发送一个包含一些变量的缓冲区

[0] -> 0,1,2 0 is keep alive, 1 means there are data, 2 means a type off error occured
[1,2,3,4] size of the actual buffer I am sending
[x(size of 1,2,3,4)] the actual 'Serialized' data buffer

【讨论】:

如果您通过在同一个线程中调用ReceiveAsync 然后WaitOne 有效地使它们同步,为什么还要使用异步API?您可以只调用同步的、阻塞的Receive() 因为这是 2 年前的,而且是 windows phone,windows phone 没有 Recieve() 如果你读过你会看到的问题。当时我需要它同步。今天的代码看起来很不一样 谢谢,我确实错过了那部分。我永远不会想到同步 api 将不可用。 :) 我的代码现在包含TaskCompletionSource<byte[]>(),摆脱了丑陋的AutoResetEvent,我现在使用async/awaitbyte[] 变成了Task<byte[]>return buffer 变成了return tcs.Task;recieveArgs_Completed 也改为容纳 TaskCompletionSource @DonaldJansen 您能否更新您对最新评论的回答?很高兴看到async/await 的实现! ?

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

在 C# 中获取套接字对象的流

C# 异步套接字概念

C# Sockets,接收大文件

C# UDP Socket:获取接收者地址

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

在 Iphone SDK 上接收带有异步 Udp 套接字的 UPS 包时出现问题