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?
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.