Problem with Sockets

  • Thread starter Thread starter Alejandro Serrano
  • Start date Start date
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);
}
}
}
 
There is no way to cancel a pending asynchronous I/O once queued.

For the listener I will do a fake connection to self to cause the accept
to complete and then close.

You should be able to call Shutdown and then Close. It sounds like Close
should cancel any pending sends or receives but I have found it to be
problematic. I will often poll availability of data. But when I must use
asynchronous I/O, and if it times out, and I need to cancel, I close
without shutdown, and catch the exceptions resulting on the end-receive.

Not sure if that is what the doctor ordered, but it seems to work for me.

Alejandro said:
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);
}
}
}
 
Back
Top