c# - .NET C# 同步接收不阻塞

标签 c# .net sockets asynchronous

最近我解决了 .Net 同步接收方法的一个奇怪行为。我需要编写一个应用程序,该应用程序具有通过发送/接收数据相互通信的节点。每个服务器都有一个同步的接收循环,在接收到一个序列化的类后,它反序列化并处理它。之后,它将这个序列化类异步发送到一些选定的节点(使用 AsynchSendTo)。

MSDN 明确指出:

"If you are using a connection-oriented Socket, the Receive method will read as much data as is available, up to the size of the buffer. If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete immediately and return zero bytes."

在我看来,这不是真的。在某些随机情况下,接收不会阻塞并在建立连接后立即返回 0 字节(非确定性情况)。我 100% 确定发件人至少发送了 1000 个字节。还有一个有趣的事实:当在 receive 之前放置 Sleep(500) 时,一切正常。以下是接收代码:

_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
    _listener.Bind(_serverEndpoint);
    _listener.Listen(Int32.MaxValue);
    while (true)
    {
        Console.WriteLine("Waiting for connection...");
        Socket handler = _listener.Accept();

        int totalBytes = 0;
        int bytesRec;
        var bytes = new byte[DATAGRAM_BUFFER];
        do
        {
            //Thread.Sleep(500);
            bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
            totalBytes += bytesRec;
        } while (bytesRec > 0);

        handler.Shutdown(SocketShutdown.Both);
        handler.Close();
    }
}
catch (SocketException e)
{
    Console.WriteLine(e);
}

还有发送部分:

public void AsynchSendTo(Datagram datagram, IPEndPoint recipient)
{

    byte[] byteDatagram = SerializeDatagram(datagram);
    try
    {
        var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket));
    }
    catch (SocketException e)
    {
        Console.WriteLine(e);
    }
}

public void ConnectCallback(IAsyncResult result)
{
    try
    {
        var stateObject = (StateObject)result.AsyncState;
        var socket = stateObject.Socket;
        socket.EndConnect(result);
        socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket);
    }
    catch (Exception ex)
    {
        Console.WriteLine("catched!" + ex.ToString());
    }
}

public void SendCallback(IAsyncResult result)
{
    try
    {
        var client = (Socket)result.AsyncState;
        client.EndSend(result);
        client.Shutdown(SocketShutdown.Both);
        client.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

class StateObject
{
    public Byte[] Data { get; set; }
    public int Size;
    public Socket Socket;
}

我的问题:我是否以错误的方式使用了同步接收?为什么有数据要接收却不阻塞事件?

最佳答案

你是搬起石头砸自己的脚。

bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);

在连接的最开始,Available 将为 0,强制它立即返回 0。相反,您应该指定缓冲区中空闲的字节数(例如 bytes.Length-totalBytes), 那么它也会阻塞。

关于c# - .NET C# 同步接收不阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8168078/

相关文章:

c# - 使用 FTP 协议(protocol)列出包含大约 2,000,000 个文件的目录

c# - 如何在 C# 中使用投影/相机技术

.net - POST 某些数据时出现 WCF 错误 400 错误请求

java - 使用java通过socket接收python json

c++ - 如何从 struct sockaddr(不是路由器 IP)获取互联网 IP?

c# - LINQ 返回分组为匿名类型的数据子集

c# - 无法替换字符串列表中的最后一个元素

.net - Thread.Abort的安全异常

.net - 在使用 pfx 证书作为安全 SOAP 请求的客户端证书之前,.NET 是否必须具有可用的根 CA 证书?

sockets - 列表中的双向套接字