Sto lavorando su un piccolo .dll dedicato alla comunicazione Tcp,Socket ObjectDisposed Eccezione
Nel mio progetto ho una classe di server che utilizza un TcpListener per accettare connessioni in entrata. Le connessioni in entrata sono memorizzate in un dizionario e gestite da lì.
codice di ogni collegamento si presenta come:
public class Connection : ConnectionBase<Coder.Coder>
{
public Connection(TcpClient client, Guid id) : base()
{
Id = id;
Client = client;
}
public void Start()
{
IsConnected = true;
Client.Client.BeginReceive(m_message, 0, m_message.Length, SocketFlags.None, new AsyncCallback(on_data_received), null);
}
public void Stop()
{
try
{
Client.Close();
handle_connection_lost(new ConnectionLostArgs(Id));
}
catch
{ }
}
public void Send(byte[] data)
{
try
{
using (NetworkStream s = Client.GetStream())
{
using (BinaryWriter w = new BinaryWriter(s))
{
var buffer = m_coder.Encode(data);
w.Write(buffer);
w.Flush();
}
}
}
catch
{ handle_connection_lost(new ConnectionLostArgs(Id)); }
}
public Guid Id { get; set; }
public TcpClient Client { get; set; }
private byte[] m_message = new byte[1024];
private void on_data_received(IAsyncResult ar)
{
try
{
Client.Client.BeginReceive(m_message, 0, m_message.Length,
SocketFlags.None, new AsyncCallback(on_data_received), null);
int bytesRead = Client.Client.EndReceive(ar);
if (bytesRead > 0)
{
byte[] data = new byte[bytesRead];
Array.Copy(m_message, data, bytesRead);
m_coder.Push(data);
}
}
catch(Exception ex)
{
Console.WriteLine("Connection::on_data_received : {0}", ex.Message);
handle_connection_lost(new ConnectionLostArgs(Id));
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
try
{
Stop();
}
catch
{ }
}
base.Dispose(disposing);
}
}
* Si prega di notare che il Coder è una classe responsabile per la decodifica e codifica i pacchetti di dati.
Oltre a quanto sopra, ho un TcpClient basato su socket (che spero di riutilizzare più tardi con Silverlight), il codice è il seguente:
public class TcpSocketClient : TcpClientBase<Coder.Coder>
{
public static TcpSocketClient Create(string host, int port)
{
if (port == 0)
return null;
return new TcpSocketClient(host, port);
}
private TcpSocketClient(string host, int port) : base()
{
IsConnected = false;
RemoteEndpoint = new DnsEndPoint(host, port);
}
public void Start()
{
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] buffer = new byte[1024];
SocketAsyncEventArgs e = new SocketAsyncEventArgs()
{
RemoteEndPoint = RemoteEndpoint,
UserToken = m_socket,
};
e.SetBuffer(buffer, 0, buffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(handle_socket_connect_completed);
m_socket.ConnectAsync(e);
}
public void Stop()
{
try
{
m_socket.Close();
m_socket.Dispose();
}
catch (ObjectDisposedException)
{ }
}
public void Send(byte[] data)
{
try
{
var buffer = m_coder.Encode(data);
SocketAsyncEventArgs e = new SocketAsyncEventArgs()
{
BufferList = new List<ArraySegment<byte>>() { new ArraySegment<byte>(buffer) },
UserToken = m_socket
};
m_socket.SendAsync(e);
}
catch (Exception ex)
{ handle_client_disconnected(ex.Message); }
}
#region Properties
public DnsEndPoint RemoteEndpoint { get; private set; }
#endregion
#region Fields
Socket m_socket;
#endregion
void handle_socket_connect_completed(object sender, SocketAsyncEventArgs e)
{
if (!m_socket.Connected)
{
handle_client_disconnected("Failed to connect");
return;
}
e.Completed -= handle_socket_connect_completed;
e.Completed += new EventHandler<SocketAsyncEventArgs>(handle_socket_async_receive);
handle_client_connected();
m_socket.ReceiveAsync(e);
}
void handle_socket_async_receive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred == 0)
{
handle_client_disconnected("Connection closed by the remote host");
try { m_socket.Close(); }
catch { }
return;
}
try
{
byte[] buffer = new byte[e.BytesTransferred];
Array.Copy(e.Buffer, buffer, e.BytesTransferred);
m_coder.Push(buffer);
}
catch { }
m_socket.ReceiveAsync(e);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
try
{
RemoteEndpoint = null;
m_socket.Close();
m_socket.Dispose();
}
catch
{ }
}
base.Dispose(disposing);
}
}
ho creato un set di unit test per entrambi.
In uno dei test invio i dati dal client al server. Lavori. In un altro test invio dati dalla connessione del server a un client. Fallimento epico. Continuo a ricevere eccezioni Socket ObjectDisposed in Connection on_data_received. Ad essere onesti non ho idea di cosa stia succedendo, quindi ho bisogno di aiuto.
sto usando .Net 4, VS 2010, il sistema operativo di La mia macchina è Win7 (se questa informazione è di alcun aiuto)
saluti, Maciek
Questo è un punto valido, tuttavia non ha risolto il problema principale. Server - dati -> Client :(Ancora faticoso per ottenere questo risultato – Maciek
Buon punto su "Nota: è necessario chiudere la connessione quando si ricevono 0 byte" –