The code shown below appears to almost work. If I create an instance of it and call "Connect" all works fine. When I call "Disconnect", sometimes everything is fine (mainly if I add a breakpoint and step through the function slowly). If I don't use a breakpoint the class(being hosted as a win forms app) seems to disappear (the form does) but visual studio still thinks it's running. In visual studio's output window I get "A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll". Can anyone spot what I'm doing wrong?
// State object for reading client data asynchronously
public class StateObject
{
private Guid ID = Guid.NewGuid();
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public class NetworkComms : IBasePanel
{
private static ILog _log = LogManager.GetCurrentClassLogger();
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
private static Socket _client = null;
private static IPEndPoint _endpoint = null;
public event ReceiveMessageEventHandler OnReceiveMessage;
public NetworkComms(string address, int port)
{
_endpoint = new IPEndPoint(GetIPAddress(address), port);
}
private IPAddress GetIPAddress(string address)
{
IPAddress ipAddress = null;
if (IPAddress.TryParse(address, out ipAddress))
{
return ipAddress;
}
else
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(address);
return ipHostInfo.AddressList[ipHostInfo.AddressList.Count() - 1];
}
}
private void ConnectCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
_log.DebugFormat("Socket connected to {0}", client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
private void Receive()
{
// 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);
}
private void ReceiveCallback(IAsyncResult ar)
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
ReceivedNewMessage(Encoding.Default.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
// Signal that all bytes have been received.
receiveDone.Set();
}
}
private static void SendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
_log.DebugFormat("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
public void SendMessage(byte[] message)
{
_client.BeginSend(message, 0, message.Length, 0, new AsyncCallback(SendCallback), _client);
sendDone.WaitOne();
}
public void Connect()
{
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.BeginConnect(_endpoint, new AsyncCallback(ConnectCallback), _client);
connectDone.WaitOne();
Receive();
}
public void Disconnect()
{
try
{
_client.Shutdown(SocketShutdown.Both);
_client.Close();
}
finally
{
_client = null;
connectDone.Reset();
sendDone.Reset();
receiveDone.Reset();
}
}
private void ReceivedNewMessage(string message)
{
if (this.OnReceiveMessage != null)
{
this.OnReceiveMessage(message);
}
}
public bool IsConnected
{
get
{
if (_client == null) return false;
return _client.Connected;
}
}
}
All of your callbacks need to handle exceptions, which are relativly common in network programming.
In this case what is probably happening is that client.EndReceive(ar);
is throwing an ObjectDisposedException because the socket is already closed when its called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With