在 C# Winform 中使用 Socket.BeginConnect() 连接服务器并且未返回 IAsyncResult 对象错误

Using Socket.BeginConnect() to connect with server in C# Winform and the IAsyncResult object was not returned error

我正在做一个应用程序,它要求我作为客户端连接到服务器并从服务器接收数据。当连接断开时,我将需要重新连接。下面是我的代码:

   public enum MySocketState
   {
       Disconnected = 0,
       Connecting,
       Connected
   }

    public Socket theDevSock = null;
    public MySocketState sockState = MySocketState.Disconnected;

    void DataProcess()
    {
        try
        {
            if (theDevSock == null || sockState == MySocketState.Disconnected)
            {
                Console.WriteLine("Trying to connect...");

                StartConnect();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    public bool StartConnect(/*AsyncCallback requestCallback*/)
    {
        Socket theSocket = null;

        try
        {
            Console.WriteLine("Start connect to server...");
            theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            theSocket.BeginConnect("192.168.1.10", 1000, ConnectCallback, theSocket);
            sockState = MySocketState.Connecting;
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("#### Unable to connect to server...");
        }
        CloseSocket();
        return false;
    }

    void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            theDevSock = (Socket)ar.AsyncState;
            if (theDevSock != null)
            {
                if (theDevSock.Connected)
                {
                    sockState = MySocketState.Connected;
                    Console.WriteLine("Server is connected...");

                    theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, this.ReceiveCallback, theDevSock);
                    return;
                }
            }
            Console.WriteLine("Failed to connect to server...");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        CloseSocket();
    }

    private void ReceiveCallback(IAsyncResult AR)
    {
        try
        {
            if (theDevSock == null)
                theDevSock = (Socket)AR.AsyncState;

            int recieved = theDevSock.EndReceive(AR);  // Error occur in this line after re-connection.

            if (recieved <= 0)
            {
                CloseSocket();
                return;
            }

            byte[] recData = new byte[recieved];
            Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
            string strData = ASCIIEncoding.ASCII.GetString(recData);
            Console.WriteLine(strData);

            //Process the data stored in recData

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            CloseSocket();
        }
        finally
        {
            try
            {
                //Start receiving again
                if (theDevSock != null)
                    theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, ReceiveCallback, theDevSock);
            }
            catch (Exception ex2)
            { }
        }
    }

    public void CloseSocket()
    {
        try
        {
            if (theDevSock != null)
            {
                if (theDevSock.Connected)
                    theDevSock.Shutdown(SocketShutdown.Both);
                theDevSock.Close();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        theDevSock = null;
        sockState = MySocketState.Disconnected;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        DataProcess();
    }
}

我正在使用计时器 (timer1_tick) 始终检测服务器是否已连接。

如果连接断开,编码可以重新连接回服务器。问题是在重新连接后,当它从服务器接收到第一个数据时,第 int recieved = theDevSock.EndReceive(AR) 行发生错误。错误信息如下:

A first chance exception of type 'System.ArgumentException' occurred in System.dll
A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll
System.ArgumentException: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult, SocketError& errorCode)
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at fform.ReceiveCallback(IAsyncResult AR) in c:\Work\Project 2015\Form1.cs:line 163
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult, SocketError& errorCode)
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at fform.Form1.ReceiveCallback(IAsyncResult AR) in c:\Work\Project 2015\Form1.cs:line 163

为什么没有返回 IAsyncResult 对象?

根据MSDN

The asynchronous BeginConnect operation must be completed by calling the EndConnect method. Typically, the method is invoked by the requestCallback delegate.

在你的

void ConnectCallback(IAsyncResult ar)

你应该在开始接收前为 EndConnect 添加一行

void ConnectCallback(IAsyncResult ar)
{
    try
    {            
        theDevSock = (Socket)ar.AsyncState;
        theDevSock.EndConnect(ar);
        //blabla
    }
}

否则连接的和接收数据的套接字可能不同

注意:我宁愿不把调用 BeginConnectSocket theSocket 放在 class 范围而不是方法范围内,然后将它传递给 theDevSock 因为它们最终都是同一个插座。