ALL,
Have the following problem.
First, here is my code:
class InternetConnector
{
private static ManualResetEvent receiveDone = new ManualResetEvent( false );
public static ManualResetEvent processingDone = new ManualResetEvent( false );
public static ConcurrentQueue<string> messages = new ConcurrentQueue<string>();
public static bool Connected;
public bool ReceiveMessage(Action<Socket> successHandler, Action<Exception> errorHandler)
{
bool receive = false;
ClientStateObject obj = new ClientStateObject();
obj.server = client;
var connectionData = new ConnectionData
{
ErrorHandler = errorHandler,
SuccessHandler = successHandler,
Socket = client,
clientObj = obj
};
if (Connected)
{
client.BeginReceive(connectionData.clientObj.buffer, 0, ClientStateObject.bufSize, 0, new AsyncCallback(ReceiveCallback), connectionData);
receive = true;
receiveDone.WaitOne();
}
return receive;
}
private static void ReceiveCallback(IAsyncResult ar)
{
ConnectionData connectionData = new ConnectionData();
bool complete = false;
try
{
connectionData = (ConnectionData)ar.AsyncState;
Socket client = connectionData.Socket;
int num = client.EndReceive(ar);
{
connectionData.clientObj.stringBuffer.Append(Encoding.ASCII.GetString(connectionData.clientObj.buffer, 0, num));
string response = connectionData.clientObj.stringBuffer.ToString();
if (response.EndsWith("&"))
complete = true;
string[] msgs = response.Split('&');
int j = 0;
if (!complete)
j++;
for (int i = 0; i < msgs.Count() - j; i++)
{
string sts = msgs[i];
if (i == 0 && receivingMessage != String.Empty)
{
sts = receivingMessage + sts;
messages.Enqueue(sts + "&" );
receivingMessage = String.Empty;
}
else
messages.Enqueue(sts + "&");
}
if (!complete)
receivingMessage += msgs[msgs.Count() - 1];
else
receivingMessage = String.Empty;
receiveDone.Set();
if (connectionData.SuccessHandler != null)
{
connectionData.SuccessHandler(client);
processingDone.WaitOne();
client.BeginReceive(connectionData.clientObj.buffer, 0, ClientStateObject.bufSize, 0, new AsyncCallback(ReceiveCallback), connectionData);
}
}
}
catch (Exception e)
{
if (connectionData.ErrorHandler != null)
connectionData.ErrorHandler(e);
}
}
}
And here is the success handler:
public partial class Form1 : Form
{
private void AsyncSuccessHandler(Socket socket)
{
if (InvokeRequired)
{
BeginInvoke(new Action( () => AsyncSuccessHandler( socket ) ));
return;
}
if (InternetConnector.messages.Count() == 0)
{
status.Text = "Signals Receiver: Connected";
status.ForeColor = Color.Green;
startStop.Text = "Stop";
isRunning = true;
create.Enabled = true;
SetGUIColorsAndValues();
client.SendMessageToConnector("First Signal Pass4&");
client.ReceiveMessage(AsyncSuccessHandler, AsyncErrorHandler);
}
else
{
SetGUIColorsAndValues();
GUIChangeOnConnection();
InternetConnector.processingDone.Set();
}
}
private void GUIChangeOnConnection()
{
for( int i = 0; i < InternetConnector.messages.Count; i++ )
{
string message;
InternetConnector.messages.TryDequeu( out message );
// process message
}
}
}
Problem:
I need to continuosly read the data from the server and display them in the GUI. I also need the GUI to be responsive to i.e. button clicks.
I also need to start n read iteration when n-1 read iteration has been finished processing and the concurrentqueue object in my code is empty.
However going thru the code in debugger I can see that BeginReceive() call in the reading callback does not wait till the end of success handler and the queue is not empty.
What am I missing? Is there a better way to achieve this?
I am also aware of SignalR library but at this pont I don’t want to use any 3rd party library.
Any help in this matter appreciated.
Thank you.
[EDIT]
Do I understand Amit’s reply correctly:
class InternetConnector
{
private static ManualResetEvent processingDone = new ManualResetEvent( false );
private static void ReceiveCallback(IAsyncResult ar)
{
ConnectionData connectionData = new ConnectionData();
bool complete = false;
try
{
connectionData = (ConnectionData)ar.AsyncState;
Socket client = connectionData.Socket;
int num = client.EndReceive(ar);
{
connectionData.clientObj.stringBuffer.Append(Encoding.ASCII.GetString(connectionData.clientObj.buffer, 0, num));
string response = connectionData.clientObj.stringBuffer.ToString();
if (response.EndsWith("&"))
complete = true;
string[] msgs = response.Split('&');
int j = 0;
if (!complete)
j++;
for (int i = 0; i < msgs.Count() - j; i++)
{
string sts = msgs[i];
if (i == 0 && receivingMessage != String.Empty)
{
sts = receivingMessage + sts;
messages.Enqueue(sts + "&" );
receivingMessage = String.Empty;
}
else
messages.Enqueue(sts + "&");
}
if (!complete)
receivingMessage += msgs[msgs.Count() - 1];
else
receivingMessage = String.Empty;
receiveDone.Set();
if (connectionData.SuccessHandler != null)
{
processingDone.WaitOne();
connectionData.SuccessHandler(client);
processingDone.Set();
client.BeginReceive(connectionData.clientObj.buffer, 0, ClientStateObject.bufSize, 0, new AsyncCallback(ReceiveCallback), connectionData);
}
}
}
catch (Exception e)
{
if (connectionData.ErrorHandler != null)
connectionData.ErrorHandler(e);
}
}
}
?
[/EDIT]
[EDIT 2]
Please see updated code.
When I set a breakpoint at the very end of the GUIChangeOnConnection() – line with the “}” – I see that the queue does have some items.
I will try to change ManualResetEvent, in the meantime.
[/EDIT 2]
If I have understood the problem correctly, you are referring to a problem at the following point of code:
If your intention is that you hit server only when you have finished processing previous data then the
SuccessHandlermust be blocking (as is obvious from your problem statement as well).Now take a look at the following lines in your
SuccessHandlerThe above code defers the execution of your
SuccessHandlerso that the UI remains responsive. Or in other words, yourSuccessHandleris not blocking.Since you are updating GUI from the
SuccessHandler, it is also important to run it from UI thread (which it is correctly doing right now).So in order to make the
SuccessHandlerblocking, you can make the following code itself run on UI thread usingInvokeRequiredmechanismSince
client.BeginReceiveis async it will not block the UI thread and you anyway wanted to runSuccessHandleron UI thread..If you don’t have access to the Form in
ReceiveCallback, you can use a waithandle to block call toclient.BeginReceivetillSuccessHandlerhas finished.ProcessingDone.Set() must be done from within
SuccessHandlerat a point where you can determine thatSuccessHandlerhas finished andclient.BeginReceiveneeds to be invoked.This is internal to your logic. From the code you have shared, it is difficult to pin point the place where you need to put ProcessingDone.Set().