すべて、
次の問題があります。まず、私のコードは次のとおりです。
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);
}
}
}
そして、これが成功ハンドラーです。
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
}
}
}
問題:サーバーからデータを継続的に読み取り、GUIに表示する必要があります。また、GUIがボタンのクリックに応答する必要があります。また、n-1回の読み取り反復の処理が終了し、コード内のconcurrentqueueオブジェクトが空になったときに、n回の読み取り反復を開始する必要があります。
ただし、デバッガーのコードを調べると、読み取りコールバックのBeginReceive()呼び出しは、成功ハンドラーの終了まで待機せず、キューは空ではないことがわかります。
私は何が欠けていますか?これを達成するためのより良い方法はありますか?
私はSignalRライブラリも知っていますが、この時点ではサードパーティのライブラリを使用したくありません。
この件での助けはありがたいです。
ありがとうございました。
[編集]
アミットの返事を正しく理解していますか:
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);
}
}
}
?
[/編集][編集2]更新されたコードを参照してください。GUIChangeOnConnection()の最後にブレークポイントを設定すると(「}」の行)、キューにいくつかの項目があることがわかります。それまでの間、ManualResetEventを変更してみます。[/編集2]