Alan Johnstone
Alan Johnstone

Reputation: 545

Cannot restart socket

I do not seem to be able to reconnect after a socket has been closed. There are several answers on the net but none seem to work.

I have a program that connects using the following code which was pretty much lifted from a Microsoft example.

private  void StartClient()
{
    DateTime time = DateTime.Now;              // Use current time
    string format = "ddd-d-HH:mm-ss";
    string timeString = time.ToString(format);
    // Connect to a remote device.
    try
    {                
        if (client != null)
            Stop();

        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        var state = new StateObject { workSocket = client };

        // Connect to the remote endpoint.
        client.BeginConnect(AprsConfig.URI, AprsConfig.Port,
            new AsyncCallback(ConnectCallback), client);
        connectDone.WaitOne();

        string logInString = string.Format("user {0} pass {1} vers Web-{3} 1.0 filter {2}\r\n",
                                AprsConfig.Callsign,
                                AprsConfig.Password,
                                AprsConfig.Filter,
                                timeString);
        // Send data to the remote device.
        appendToDebugFile("Sent to server: " + logInString);

        Send(client, logInString);
        sendDone.WaitOne();

        // Receive the response from the remote device.
        Receive(client);

    }
    catch (Exception e)
    {
        // Console.WriteLine(e.ToString());
        appendToDebugFile("StartClient failed : " + e.ToString());
        if (retryCount < 10)
        { 
            appendToDebugFile("Attempt to restart again");
            retryCount++;
            restartClient
        }
    }
    retryCount=0;
}

It connects properly without problems the fist time. Receive() calls itself again and so on. I do not think it is relevant but here is the code

private  void Receive(Socket client)
{
    try
    {
        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = client;

        // Begin receiving the data from the remote device.
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReceiveCallback), state);
    }
    catch (Exception e)
    {
        //Console.WriteLine(e.ToString());
        appendToDebugFile("Receive failed : " + e.ToString());
    }
}

and

 private void ReceiveCallback(IAsyncResult ar)
 {
    try
    {
        // Retrieve the state object and the client socket 
        // from the asynchronous state object.

        var state = (StateObject)ar.AsyncState;

        if (!state.workSocket.Connected)
        {
            reStartClient("Error: state.workSocket.Connected =false - Restarting");
            return;
        }

        var client = state.workSocket;

        // Read data from the remote device.
        var bytesRead = client.EndReceive(ar);

        if (bytesRead == 0)
        {
            reStartClient("ERROR: bytes==0 - Restarting");
            return;
        }

        // quickly store the buffer
        storeBytes buff = new storeBytes(state.buffer, bytesRead);
        byteQueue.Enqueue(buff);
        string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReceiveCallback), state);
        // setoff the readBytes Thread
        readBytesWaitHandle.Set();
    }
    catch(IOException e)
    {
        appendToDebugFile("ReceiveCallback failed : " + e.ToString());
    }
}

I am rightly or wrongly assuming that if I get zero bytes read then the connection has failed so I try to close the connection and start again. here is the code which I got from another Stackoverflow answer.

 private void reStartClient(string reason)
 {
     appendToDebugFile(reason);
     if (client != null && client.Connected)
     {
         client.Shutdown(SocketShutdown.Both);

         client.Disconnect(true);
         if (client.Connected)
             appendToDebugFile("We're still connnected");
         else
             appendToDebugFile("We're disconnected");
         client.Close();
     }
     client = null;
     // appendToDebugFile("Waiting 10 secs");
     // System.Threading.Thread.Sleep(10000);
     StartClient();
 }

As you can see I have been trying delays but that has not worked.

As it goes through StartClient after restarting it seems to connect but throws an error when it tries to send. Here is a part of the log file

Attempt to restart again Socket connected to 37.187.40.234:14580 Stopped 13/08/2014 14:18:18 We're disconnected Sent to server: user 2E0ATJ pass -1 vers Web-Wed-13-14:18-18 1.0 filter r/51.6/-.8/2000 -q/C

StartClient failed : System.Net.Sockets.SocketException (0x80004005): A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied at WebAPRS.PacketListener.Send(Socket client, String data) in c:\Users\Alan\Documents\Visual Studio 2013\Projects\WebAPRS\WebAPRS\Connection.cs:line 188 at WebAPRS.PacketListener.StartClient() in c:\Users\Alan\Documents\Visual Studio 2013\Projects\WebAPRS\WebAPRS\Connection.cs:line 64 Attempt to restart again Stopped 13/08/2014 14:18:18 Sent to server: user 2E0ATJ pass -1 vers Web-Wed-13-14:18-18 1.0 filter r/51.6/-.8/2000 -q/C

StartClient failed : System.Net.Sockets.SocketException (0x80004005): A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied at WebAPRS.PacketListener.Send(Socket client, String data) in c:\Users\Alan\Documents\Visual Studio 2013\Projects\WebAPRS\WebAPRS\Connection.cs:line 188 at WebAPRS.PacketListener.StartClient() in c:\Users\Alan\Documents\Visual Studio 2013\Projects\WebAPRS\WebAPRS\Connection.cs:line 64 Attempt to restart again Stopped 13/08/2014 14:18:18

Hopefully somebody can tell me what I am doing wrong.

Upvotes: 0

Views: 1058

Answers (1)

C.Evenhuis
C.Evenhuis

Reputation: 26436

Most probably connectDone is a ManualResetEvent which was put in a signalled state on the previous connection attempt, and was never reset. This causes WaitOne() to not block, and a the code attempts to send data before the connection was established.

You could reset it prior to connecting:

// Connect to the remote endpoint.
connectDone.Reset();
client.BeginConnect(AprsConfig.URI, AprsConfig.Port, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();

Alternatively you could use AutoResetEvent if no other threads monitor connectDone.

Upvotes: 1

Related Questions