?
?lafur Helgi R?gnvaldsson
I'm building a server application which accepts socket connections and
I ran into some problems.
The socket is asynchronous and therefore uses the BeginXXX and EndXXX
methods in the Socket class to receive data. I also use a
ManualResetEvent to signal the main thread when data arrives.
Here is the code I'm running:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
namespace SocketClient
{
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 256;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
class SocketClient
{
private const int port = 11000;
private bool timeout = true;
private ManualResetEvent connectDone = new ManualResetEvent(false);
private ManualResetEvent sendDone = new ManualResetEvent(false);
private ManualResetEvent receiveDone = new ManualResetEvent(false);
[STAThread]
static void Main(string[] args)
{
SocketClient socketClient = new SocketClient();
socketClient.StartClient();
Console.ReadLine();
}
private void StartClient()
{
try
{
IPHostEntry ipHostInfo = Dns.Resolve("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect( remoteEP, new AsyncCallback(ConnectCallback),
client);
connectDone.WaitOne();
for(int i=0; i<3; i++)
{
Send(client,"This is a test<EOF>" + i);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne(3000, true);
if(timeout == true)
{
Console.WriteLine("Timed out...");
}
else
{
Console.WriteLine("Response received");
}
}
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
client.EndConnect(ar);
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Receive(Socket client)
{
try
{
StateObject state = new StateObject();
state.workSocket = client;
client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
timeout = true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ReceiveCallback( IAsyncResult ar )
{
try
{
timeout = false;
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = 0;
try
{
bytesRead = client.EndReceive(ar);
}
catch(ObjectDisposedException)
{
//the socket has been closed
}
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
receiveDone.Set();
}
else
{
//disconnected
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0, new
AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
int bytesSent = client.EndSend(ar);
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
The code above works fine and the server only sends data back to the
client when "This is a test<EOF>2" is received otherwise I have a
timeout. The output of this is:
Timed out...
Timed out...
Response received
However the beginReceive function is called twice without the
ReceiveCallback function being called. The ReceiveCallback function
is only called the third time the server sends the data back to the
client. When the client.Close() function is called the
ReceiveCallback function is called twice, since there were 2 receive
functions pending. The ReceiveCallback function calls EndReceive
which in turn throws an ObjectDisposedException which I catch and
ignore.
Here is my question, is this the proper way to implement a timeout
with an asynchronous socket or is it a bad idea to call beginReceive
with a pending receive ?
Ólafur Helgi.
I ran into some problems.
The socket is asynchronous and therefore uses the BeginXXX and EndXXX
methods in the Socket class to receive data. I also use a
ManualResetEvent to signal the main thread when data arrives.
Here is the code I'm running:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
namespace SocketClient
{
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 256;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
class SocketClient
{
private const int port = 11000;
private bool timeout = true;
private ManualResetEvent connectDone = new ManualResetEvent(false);
private ManualResetEvent sendDone = new ManualResetEvent(false);
private ManualResetEvent receiveDone = new ManualResetEvent(false);
[STAThread]
static void Main(string[] args)
{
SocketClient socketClient = new SocketClient();
socketClient.StartClient();
Console.ReadLine();
}
private void StartClient()
{
try
{
IPHostEntry ipHostInfo = Dns.Resolve("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect( remoteEP, new AsyncCallback(ConnectCallback),
client);
connectDone.WaitOne();
for(int i=0; i<3; i++)
{
Send(client,"This is a test<EOF>" + i);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne(3000, true);
if(timeout == true)
{
Console.WriteLine("Timed out...");
}
else
{
Console.WriteLine("Response received");
}
}
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
client.EndConnect(ar);
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Receive(Socket client)
{
try
{
StateObject state = new StateObject();
state.workSocket = client;
client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
timeout = true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ReceiveCallback( IAsyncResult ar )
{
try
{
timeout = false;
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = 0;
try
{
bytesRead = client.EndReceive(ar);
}
catch(ObjectDisposedException)
{
//the socket has been closed
}
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
receiveDone.Set();
}
else
{
//disconnected
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0, new
AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
int bytesSent = client.EndSend(ar);
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
The code above works fine and the server only sends data back to the
client when "This is a test<EOF>2" is received otherwise I have a
timeout. The output of this is:
Timed out...
Timed out...
Response received
However the beginReceive function is called twice without the
ReceiveCallback function being called. The ReceiveCallback function
is only called the third time the server sends the data back to the
client. When the client.Close() function is called the
ReceiveCallback function is called twice, since there were 2 receive
functions pending. The ReceiveCallback function calls EndReceive
which in turn throws an ObjectDisposedException which I catch and
ignore.
Here is my question, is this the proper way to implement a timeout
with an asynchronous socket or is it a bad idea to call beginReceive
with a pending receive ?
Ólafur Helgi.