//============ // クライアント接続後処理メソッド // 本サーバーにクライアントが接続してきたら、本メソッドの処理を // 実行します。具体的には、まず、クライアントに要求電文(命令) // を提出するよう通知します(すなわち、これは、サーバーに接続さ // れたことをクライアントに通知することを意味しています)。次に、 // クライアントから要求電文が送られてくるのを待機します。 // 第1引数: 非同期操作のステータス private void WaitForConnectionCallBack(IAsyncResult iar) { try { // パイプの取得 System.IO.Pipes.NamedPipeServerStream pipe_Server = (System.IO.Pipes.NamedPipeServerStream)iar.AsyncState; //------------ // 非同期操作完了 //------------ // クライアントが接続するのを待機する非同期操作を終了します。 pipe_Server.EndWaitForConnection(iar); // 以下の処理は、本サーバーにクライアントが接続された後に実行されます。 // (それまで待機中となり、実行が開始されない) //------------ // クライアントへ接続通知を送信 //------------ // ストリームに対して、文字データーを読み書きするオブジェクトを生成 AccessStream ss = new AccessStream(pipe_Server); // 送信データーを書き込み // --- クライアントに要求電文(命令)を提出するよう通知します。 // 具体的には、 // 「サーバーはクライアントに命令を提出するよう要求している」 // と言う意味の英文メッセージを名前付きパイプに書き込む。 ss.WriteString( "A connection succeeded.", "shift_jis"); //------------ // クライアントから要求電文を受信 //------------ // 要求電文受信待機 ReceiveOrder(this); } // 名前付きパイプが壊れているなどの異常が発生した場合 catch (System.IO.IOException ex) { // エラー処理 System.Windows.Forms.MessageBox.Show(ex.Message, "エラー通知"); } }
//============ // 要求電文受信待機 // クライアントから要求電文(命令)を受信します。 // 第1引数: サーバークラス(各スレッド間の情報伝達に使用) void ReceiveOrder(PipeServer p_server) { // Int32型のデーターのサイズ(Int32型サイズ) Int32 Int_Size = sizeof(Int32); // ヘッダー // Int32型データー用バイト型配列 // 後にint型データーを、バイト型配列に格納する時に使う。 byte[] HeaderBuffer = new byte[Int_Size]; // 非同期操作のステータスを表すオブジェクト。 IAsyncResult result; try { // 要求用受信電文のヘッダーを取得する。 // かつ、その後の処理を行なうメソッドを指定。 result = p_server.pipeServer.BeginRead(HeaderBuffer, 0, HeaderBuffer.Length, null, null); } catch (InvalidOperationException) //disconnected/disposed { return; } //------------ // 非同期操作完了 //------------ // 非同期処理が完了するまで待つ。 result.AsyncWaitHandle.WaitOne(); int bytesRead; try { // 非同期読み取りを完了するまで待機する操作を終了します。 bytesRead = p_server.pipeServer.EndRead(result); } catch (System.IO.IOException) //closed { return; } // 以下の処理は、クライアントから来た要求電文を読み始めてから // 実行されます。正確には、要求電文のヘッダーを読み終えた直後 // に、以下の処理の実行が開始されます。 // (それまで待機中となり、実行が開始されない) //------------ // ヘッダーの復元 // --- ヘッダーは、既に読み込み済みなので、後はそれをInt32型に復元する。 //------------ // 取得したデーターをバイト型配列からint型に変換 Int32 len = BitConverter.ToInt32(HeaderBuffer, 0); //------------ // データー本体読み込み //------------ // データー本体用バイト型配列 // 後にデーター本体を、バイト型配列に格納する時に使う。 byte[] inBuffer = new byte[len]; // ストリームからデーター本体を読み込む。 p_server.pipeServer.Read(inBuffer, 0, len); // 取得したデーターをバイト型配列からstring型に変換 // (バイト型配列 ---> ユニコードstring 変換) string OrderMessage; // 取得文字を格納するオブジェクト StringBytesController.ChangeBinaryToUnicodeStr( inBuffer, "shift_jis", out OrderMessage); // 電文受信時に起動させるメソッドを実行 OnReceiveCall(DateTime.Now, OrderMessage); // 返信用電文作成 // クライアントに返す返信用電文を作成します。なお、今までの // 流れでは、 // ss.WriteString("返信内容", "shift_jis"); // で返信したいところです。しかし、マイクロソフトのホームペ // ージ(MSDNホームページ)を見ますと、返信はRunAsClient() // と言うメソッドで行なうようなので、下記コードもそのように // します。 // ストリームに対して、文字データーを読み書きするオブジェクトを生成 AccessStream ss = new AccessStream(p_server.pipeServer); // 返信用メッセージをストリームに書き込む。 ss.WriteString(SendData, "shift_jis"); // 名前付きパイプのクローズ p_server.pipeServer.Close(); p_server.pipeServer.Dispose(); p_server.pipeServer = null; // 返信送信完了時に起動させるメソッドを実行 OnFinishTransmission(DateTime.Now); }
//============ // 接続通知受信メソッド // サーバーへ接続すると、無事に接続されたことを知らせる通知用電文が、 // サーバーから送られて来る仕様にしてあります。その通知を本メソッド // で受信します。 // 第1引数: クライアントクラス(各スレッド間の情報伝達に使用) private void ReceiveConnectionNotice(PipeClient client) { // 非同期操作のステータスを表すオブジェクト。 IAsyncResult result; try { // 接続通知用受信電文のヘッダーを取得する。 // かつ、その後の処理を行なうメソッドを指定。 result = client.pipeClient.BeginRead(client.HeaderBuffer, 0, client.HeaderBuffer.Length, null, null); } catch (InvalidOperationException) //disconnected/disposed { return; } //------------ // 非同期操作完了 //------------ // 非同期処理が完了するまで待つ。 result.AsyncWaitHandle.WaitOne(); int bytesRead; try { // 非同期読み取りを完了するまで待機する操作を終了します。 bytesRead = client.pipeClient.EndRead(result); } catch (System.IO.IOException) //closed { return; } // 以下の処理は、サーバーから来た接続通知を読み始めてから実行 // されます。正確には、接続通知電文のヘッダーを読み終えた直後 // に、以下の処理の実行が開始されます。 // (それまで待機中となり、実行が開始されない) //------------ // ヘッダーの復元 // --- ヘッダーは、既に読み込み済みなので、後はそれをInt32型に復元する。 //------------ // 取得したデーターをバイト型配列からint型に変換 Int32 len = BitConverter.ToInt32(client.HeaderBuffer, 0); //------------ // データー本体読み込み //------------ // データー本体用バイト型配列 // 後にデーター本体を、バイト型配列に格納する時に使う。 byte[] inBuffer = new byte[len]; // ストリームからデーター本体を読み込む。 client.pipeClient.Read(inBuffer, 0, len); // 取得したデーターをバイト型配列からstring型に変換 // (バイト型配列 ---> ユニコードstring 変換) string temp; // 取得文字を格納するオブジェクト StringBytesController.ChangeBinaryToUnicodeStr( inBuffer, "shift_jis", out temp); // サーバーに接続されたか確認。 if (temp == "A connection succeeded.") { // ストリームに対して、文字データーを読み書きするオブジェクトを生成 AccessStream ss = new AccessStream(pipeClient); // コマンド(命令)をサーバーへ送信。 ss.WriteString(client.CommandMessage, "shift_jis"); // サーバープロセスから通達されたメッセージを取得する。 client.ReceiveReply(client); } }