static class AsyncSocketListener
{
private static ushort port = 8080;
private static ushort limit = 250;
private static ManualResetEvent mre = new ManualResetEvent(false);
private static Dictionary<int, StateObject> clients = new Dictionary<int, StateObject>();
#region Event handler
public delegate void MessageReceivedHandler(int id, String msg);
public static event MessageReceivedHandler MessageReceived;
public delegate void MessageSubmittedHandler(int id, bool close);
public static event MessageSubmittedHandler MessageSubmitted;
#endregion
/* Starts the AsyncSocketListener */
public static void StartListening()
{
IPHostEntry host = Dns.GetHostEntry(String.Empty);
IPAddress ip = host.AddressList[3];
IPEndPoint socket = new IPEndPoint(ip, port);
try
{
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(socket);
listener.Listen(limit);
while (true)
{
mre.Reset();
listener.BeginAccept(new AsyncCallback(OnClientConnect), listener);
mre.WaitOne();
}
}
}
catch (SocketException)
{
// TODO:
}
}
/* Gets a socket from the clients dictionary by his Id. */
private static StateObject getClient(int id)
{
StateObject state = new StateObject();
return clients.TryGetValue(id, out state) ? state : null;
}
/* Checks if the socket is connected. */
public static Booleanbool IsConnected(int id)
{
StateObject state = getClient(id);
return !(state.listener.Poll(1000, SelectMode.SelectRead) && state.listener.Available == 0);
}
/* Add a socket to the clients dictionary. Lock clients temporary to handle multiple access.
* ReceiveCallback raise a event, after the message receive complete. */
#region Receive data
public static void OnClientConnect(IAsyncResult result)
{
mre.Set();
StateObject state = new StateObject();
try
{
lock (clients)
{
state.Id = !clients.Any() ? 1 : clients.Keys.Max() + 1;
clients.Add(state.Id, state);
Console.WriteLine("Client connected. Get Id " + state.Id);
}
state.listener = (Socket)result.AsyncState;
state.listener = state.listener.EndAccept(result);
state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
catch (SocketException)
{
// TODO:
}
}
public static void ReceiveCallback(IAsyncResult result)
{
StateObject state = (StateObject)result.AsyncState;
try
{
int receive = state.listener.EndReceive(result);
if (receive > 0)
state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, receive));
if (receive == StateObject.BufferSize)
state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
else
{
MessageReceived(state.Id, state.sb.ToString());
state.sb = new StringBuilder();
}
}
catch (SocketException)
{
// TODO:
}
}
#endregion
/* Send(int id, String msg, bool close) use bool to close the connection after the message sent. */
#region Send data
public static void Send(int id, String msg, bool close)
{
StateObject state = getClient(id);
if (state == null)
throw new Exception("Client does not exist.");
if (!IsConnected(state.Id))
throw new Exception("Destination socket is not connected.");
try
{
byte[] send = Encoding.UTF8.GetBytes(msg);
state.Close = close;
state.listener.BeginSend(send, 0, send.Length, SocketFlags.None, new AsyncCallback(SendCallback), state);
}
catch (SocketException)
{
// TODO:
}
catch (ArgumentException)
{
// TODO:
}
}
private static void SendCallback(IAsyncResult result)
{
StateObject state = (StateObject)result.AsyncState;
try
{
state.listener.EndSend(result);
}
catch (SocketException)
{
// TODO:
}
catch (ObjectDisposedException)
{
// TODO:
}
finally
{
MessageSubmitted(state.Id, state.Close);
}
}
#endregion
public static void Close(int id)
{
StateObject state = getClient(id);
if (state == null)
throw new Exception("Client does not exist.");
try
{
state.listener.Shutdown(SocketShutdown.Both);
state.listener.Close();
}
catch (SocketException)
{
// TODO:
}
finally
{
lock (clients)
{
clients.Remove(state.Id);
Console.WriteLine("Client disconnected with Id {0}", state.Id);
}
}
}
}
class AsyncClient : IDisposable
{
private const ushort port = 8080;
private Socket listener = null;
private bool close = false;
public ManualResetEvent connected = new ManualResetEvent(false);
public ManualResetEvent sent = new ManualResetEvent(false);
public ManualResetEvent received = new ManualResetEvent(false);
#region Event handler
public delegate void ConnectedHandler(AsyncClient a);
public static event ConnectedHandler Connected;
public delegate void MessageReceivedHandler(AsyncClient a, String msg);
public static event MessageReceivedHandler MessageReceived;
public delegate void MessageSubmittedHandler(AsyncClient a, bool close);
public static event MessageSubmittedHandler MessageSubmitted;
#endregion
/* Starts the AsyncClient */
public AsyncClient()
{
}
public void StartClient()
{
IPHostEntry host = Dns.GetHostEntry(String.Empty);
IPAddress ip = host.AddressList[3];
IPEndPoint socket = new IPEndPoint(ip, port);
try
{
this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.listener.BeginConnect(socket, new AsyncCallback(OnConnectCallback), listener);
connected.WaitOne();
Connected(this);
}
catch (SocketException)
{
// TODO:
}
}
public Booleanbool IsConnected()
{
return !(this.listener.Poll(1000, SelectMode.SelectRead) && this.listener.Available == 0);
}
private void OnConnectCallback(IAsyncResult result)
{
Socket server = (Socket)result.AsyncState;
try
{
server.EndConnect(result);
connected.Set();
}
catch (SocketException)
{
}
}
#region Receive data
public void Receive()
{
StateObject state = new StateObject();
state.listener = this.listener;
state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
private void ReceiveCallback(IAsyncResult result)
{
StateObject state = (StateObject)result.AsyncState;
int receive = state.listener.EndReceive(result);
if (receive > 0)
state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, receive));
if (receive == StateObject.BufferSize)
state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
else
{
MessageReceived(this, state.sb.ToString());
state.sb = new StringBuilder();
received.Set();
}
}
#endregion
#region Send data
public void Send(String msg, bool close)
{
if (!IsConnected())
throw new Exception("Destination socket is not connected.");
byte[] response = Encoding.UTF8.GetBytes(msg);
this.close = close;
this.listener.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(SendCallback), this.listener);
}
private void SendCallback(IAsyncResult result)
{
try
{
Socket resceiver = (Socket)result.AsyncState;
resceiver.EndSend(result);
}
catch (SocketException)
{
// TODO:
}
catch (ObjectDisposedException)
{
// TODO;
}
MessageSubmitted(this, this.close);
sent.Set();
}
#endregion
private void Close()
{
try
{
if (IsConnected())
{
this.listener.Shutdown(SocketShutdown.Both);
this.listener.Close();
}
}
catch (SocketException)
{
// TODO:
}
}
public void Dispose()
{
connected.Close();
sent.Close();
received.Close();
Close();
}
}
Edit:
At the moment the client could connect and send a message to the server. The server could reply on it. But it is not possible to exchange messages after this. I’m trying to fix this, but I doesn’t find a solution any idea?