Reputation: 545
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
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