.NET C#同步接收不会阻止

rad*_*usz 6 .net c# sockets asynchronous

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

MSDN清楚地说:

"如果您使用的是面向连接的套接字,则Receive方法将读取尽可能多的数据,最大可达缓冲区大小.如果远程主机使用Shutdown方法关闭Socket连接,并且所有可用数据都有收到后,Receive方法将立即完成并返回零字节."

在我的情况下,这不是真的.在接收没有阻塞并且在建立连接之后立即返回0字节(非确定性的位置)时,存在一些随机情况.我百分百肯定发件人发送的是至少1000字节.另一个有趣的事实是:在接收睡眠之前(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);
}
Run Code Online (Sandbox Code Playgroud)

发送部分:

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;
}
Run Code Online (Sandbox Code Playgroud)

我的问题:我是否以错误的方式使用同步接收?尽管有数据要接收,为什么它不会阻止事件?

Luc*_*ero 6

你在脚下射击自己.

bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
Run Code Online (Sandbox Code Playgroud)

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


Tud*_*dor 6

您可能在这里遇到并发问题.在您接受连接后,您直接跳到接收.发件人进程可能没有足够的时间来handler.Available接收要发送的呼叫,因此您的状态为0且接收返回.

这也是添加500毫秒睡眠时不会出现"错误"的原因.