Search code examples
c#winformssocketstcpclienttcp

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


I'm doing an application which require me as a client side to connect to a server and receive data from the server. I will need to do re-connection when the connection is disconnected. Below is my code:

   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();
    }
}

I'm using a timer (timer1_tick) to always detect whether or not the server is connected.

The coding have no problem in reconnecting back to the server if the connection has been disconnected. The problem is after reconnection and when it receive the first data from the server, an error occur at line int recieved = theDevSock.EndReceive(AR). The error message is as below:

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

Why is it the IAsyncResult object was not returned?


Solution

  • According to MSDN

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

    In your

    void ConnectCallback(IAsyncResult ar)
    

    You should put a line for EndConnect before begin receive

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

    Else the socket which is connected and which receives the data might be different

    Note: I would prefer not to put Socket theSocket for calling BeginConnect in the class scope rather than method scope, and then pass it to theDevSock since they are the same socket ultimately.