A
Alejandro Serrano
Hi, I'm developing a program who needs that user communicate via TCP
over the net. One will be the listener and the other one the client, as
usual. I've implemented the code as two classes deriving from a common
interface. Everything seems to work OK until I use the Close() method.
I've tried both using EndReceive(result) or commenting it. If I use it,
the connection is not closed. If not, both applications close
themselves: the one on the end-point with a error (not an exception, but
an Windows fatal error). The code is below.
Thanks in advance. If someone could help me, I'd be very pleased.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ThreatOfChaos.Connection
{
// This two classes are used in callbacks
class MessageEventArgs : System.EventArgs
{
string message;
public MessageEventArgs(string Message)
{
this.message = Message;
}
public string Message
{
get
{ return message; }
}
}
class ConnectionEventArgs : System.EventArgs
{
Socket socket;
public ConnectionEventArgs(Socket Socket)
{
this.socket = Socket;
}
public Socket Socket
{
get { return socket; }
}
}
public delegate void MessageReceivedHandler(object sender,
MessageEventArgs e);
public delegate void ConnectionEstablishedHandler(object sender,
ConnectionEventArgs e);
public delegate void ConnectionClosedHandler(object sender);
// This is the interface that both
// client and server implement.
public interface IConnection
{
event MessageReceivedHandler MessageReceived;
event ConnectionEstablishedHandler ConnectionEstablished;
event ConnectionClosedHandler ConnectionClosed;
Socket Socket { get; }
void Start(int Port, IPAddress address);
void Send(byte[] buffer);
void Send(string data);
void Close();
}
public class SocketPacket
{
public Socket Socket;
public byte[] DataBuffer = new byte[1000000];
}
// This is the Client implementation
public class ClientConnection : IConnection
{
public event MessageReceivedHandler MessageReceived;
public event ConnectionEstablishedHandler ConnectionEstablished;
public event ConnectionClosedHandler ConnectionClosed;
Socket client;
AsyncCallback dataReceived;
IAsyncResult result;
public Socket Socket
{
get { return client; }
}
public void Start(int Port, IPAddress address)
{
client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(address, Port);
client.Connect(endPoint);
if (client.Connected)
{
if (ConnectionEstablished != null)
{
ConnectionEventArgs e = new
ConnectionEventArgs(client);
ConnectionEstablished(this, e);
}
WaitForData();
}
else
{
throw new Exception("Client not connected");
}
}
public void WaitForData()
{
if (client.Connected)
{
if (dataReceived == null)
dataReceived = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.Socket = client;
result = client.BeginReceive(packet.DataBuffer, 0,
packet.DataBuffer.Length, SocketFlags.None,
dataReceived, packet);
}
else
{
Close();
}
}
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket packet = (SocketPacket)asyn.AsyncState;
int iRx = packet.Socket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
Decoder d = Encoding.Unicode.GetDecoder();
int charLen = d.GetChars(packet.DataBuffer, 0,
iRx, chars, 0);
string data = new string(chars);
if (MessageReceived != null)
{
MessageEventArgs e = new MessageEventArgs(data);
MessageReceived(this, e);
}
WaitForData();
}
public void Send(byte[] buffer)
{
if (client.Connected)
{
client.Send(buffer);
}
else
{
Close();
}
}
public void Send(string data)
{
byte[] byData = Encoding.Unicode.GetBytes(data);
Send(byData);
}
public void Close()
{
client.EndReceive(result);
client.Close();
Send("");
if (ConnectionClosed != null)
ConnectionClosed(this);
}
}
// This is the Server implementation
public class ServerConnection : IConnection
{
public event MessageReceivedHandler MessageReceived;
public event ConnectionEstablishedHandler ConnectionEstablished;
public event ConnectionClosedHandler ConnectionClosed;
Socket listener;
Socket workerSocket;
AsyncCallback dataReceived;
IAsyncResult result;
public void Start(int Port, IPAddress address)
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, Port);
listener.Bind(ipLocal);
listener.Listen(4);
listener.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
public void OnClientConnect(IAsyncResult asyn)
{
workerSocket = listener.EndAccept(asyn);
if (ConnectionEstablished != null)
{
ConnectionEventArgs e = new
ConnectionEventArgs(workerSocket);
ConnectionEstablished(this, e);
}
WaitForData(workerSocket);
}
public void WaitForData(Socket socket)
{
if (socket.Connected)
{
if (dataReceived == null)
dataReceived = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.Socket = socket;
result = socket.BeginReceive(packet.DataBuffer, 0,
packet.DataBuffer.Length, SocketFlags.None,
dataReceived, packet);
}
else
{
Close();
}
}
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket packet = (SocketPacket)asyn.AsyncState;
int iRx = packet.Socket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
Decoder d = Encoding.Unicode.GetDecoder();
int charLen = d.GetChars(packet.DataBuffer, 0,
iRx, chars, 0);
string data = new string(chars);
if (MessageReceived != null)
{
MessageEventArgs e = new MessageEventArgs(data);
MessageReceived(this, e);
}
WaitForData(packet.Socket);
}
public Socket Socket
{
get
{
return (Socket)listener;
}
}
public void Send(byte[] buffer)
{
if (workerSocket.Connected)
{
workerSocket.Send(buffer);
}
else
{
Close();
}
}
public void Send(string data)
{
byte[] byData = Encoding.Unicode.GetBytes(data);
Send(byData);
}
public void Close()
{
workerSocket.EndReceive(result);
workerSocket.Close();
listener.Close();
if (ConnectionClosed != null)
ConnectionClosed(this);
}
}
}
over the net. One will be the listener and the other one the client, as
usual. I've implemented the code as two classes deriving from a common
interface. Everything seems to work OK until I use the Close() method.
I've tried both using EndReceive(result) or commenting it. If I use it,
the connection is not closed. If not, both applications close
themselves: the one on the end-point with a error (not an exception, but
an Windows fatal error). The code is below.
Thanks in advance. If someone could help me, I'd be very pleased.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ThreatOfChaos.Connection
{
// This two classes are used in callbacks
class MessageEventArgs : System.EventArgs
{
string message;
public MessageEventArgs(string Message)
{
this.message = Message;
}
public string Message
{
get
{ return message; }
}
}
class ConnectionEventArgs : System.EventArgs
{
Socket socket;
public ConnectionEventArgs(Socket Socket)
{
this.socket = Socket;
}
public Socket Socket
{
get { return socket; }
}
}
public delegate void MessageReceivedHandler(object sender,
MessageEventArgs e);
public delegate void ConnectionEstablishedHandler(object sender,
ConnectionEventArgs e);
public delegate void ConnectionClosedHandler(object sender);
// This is the interface that both
// client and server implement.
public interface IConnection
{
event MessageReceivedHandler MessageReceived;
event ConnectionEstablishedHandler ConnectionEstablished;
event ConnectionClosedHandler ConnectionClosed;
Socket Socket { get; }
void Start(int Port, IPAddress address);
void Send(byte[] buffer);
void Send(string data);
void Close();
}
public class SocketPacket
{
public Socket Socket;
public byte[] DataBuffer = new byte[1000000];
}
// This is the Client implementation
public class ClientConnection : IConnection
{
public event MessageReceivedHandler MessageReceived;
public event ConnectionEstablishedHandler ConnectionEstablished;
public event ConnectionClosedHandler ConnectionClosed;
Socket client;
AsyncCallback dataReceived;
IAsyncResult result;
public Socket Socket
{
get { return client; }
}
public void Start(int Port, IPAddress address)
{
client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(address, Port);
client.Connect(endPoint);
if (client.Connected)
{
if (ConnectionEstablished != null)
{
ConnectionEventArgs e = new
ConnectionEventArgs(client);
ConnectionEstablished(this, e);
}
WaitForData();
}
else
{
throw new Exception("Client not connected");
}
}
public void WaitForData()
{
if (client.Connected)
{
if (dataReceived == null)
dataReceived = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.Socket = client;
result = client.BeginReceive(packet.DataBuffer, 0,
packet.DataBuffer.Length, SocketFlags.None,
dataReceived, packet);
}
else
{
Close();
}
}
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket packet = (SocketPacket)asyn.AsyncState;
int iRx = packet.Socket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
Decoder d = Encoding.Unicode.GetDecoder();
int charLen = d.GetChars(packet.DataBuffer, 0,
iRx, chars, 0);
string data = new string(chars);
if (MessageReceived != null)
{
MessageEventArgs e = new MessageEventArgs(data);
MessageReceived(this, e);
}
WaitForData();
}
public void Send(byte[] buffer)
{
if (client.Connected)
{
client.Send(buffer);
}
else
{
Close();
}
}
public void Send(string data)
{
byte[] byData = Encoding.Unicode.GetBytes(data);
Send(byData);
}
public void Close()
{
client.EndReceive(result);
client.Close();
Send("");
if (ConnectionClosed != null)
ConnectionClosed(this);
}
}
// This is the Server implementation
public class ServerConnection : IConnection
{
public event MessageReceivedHandler MessageReceived;
public event ConnectionEstablishedHandler ConnectionEstablished;
public event ConnectionClosedHandler ConnectionClosed;
Socket listener;
Socket workerSocket;
AsyncCallback dataReceived;
IAsyncResult result;
public void Start(int Port, IPAddress address)
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, Port);
listener.Bind(ipLocal);
listener.Listen(4);
listener.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
public void OnClientConnect(IAsyncResult asyn)
{
workerSocket = listener.EndAccept(asyn);
if (ConnectionEstablished != null)
{
ConnectionEventArgs e = new
ConnectionEventArgs(workerSocket);
ConnectionEstablished(this, e);
}
WaitForData(workerSocket);
}
public void WaitForData(Socket socket)
{
if (socket.Connected)
{
if (dataReceived == null)
dataReceived = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.Socket = socket;
result = socket.BeginReceive(packet.DataBuffer, 0,
packet.DataBuffer.Length, SocketFlags.None,
dataReceived, packet);
}
else
{
Close();
}
}
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket packet = (SocketPacket)asyn.AsyncState;
int iRx = packet.Socket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
Decoder d = Encoding.Unicode.GetDecoder();
int charLen = d.GetChars(packet.DataBuffer, 0,
iRx, chars, 0);
string data = new string(chars);
if (MessageReceived != null)
{
MessageEventArgs e = new MessageEventArgs(data);
MessageReceived(this, e);
}
WaitForData(packet.Socket);
}
public Socket Socket
{
get
{
return (Socket)listener;
}
}
public void Send(byte[] buffer)
{
if (workerSocket.Connected)
{
workerSocket.Send(buffer);
}
else
{
Close();
}
}
public void Send(string data)
{
byte[] byData = Encoding.Unicode.GetBytes(data);
Send(byData);
}
public void Close()
{
workerSocket.EndReceive(result);
workerSocket.Close();
listener.Close();
if (ConnectionClosed != null)
ConnectionClosed(this);
}
}
}