忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

名前付きパイプを使ったプロセス間通信についてその2(複数クライアントとの通信)

名前付きパイプを使ったクライアントプログラムとの通信の説明は以下の記事で行いましたが、 今回はこれを複数のクライアントとの通信が出来る様に変更してみました。
名前付きパイプを使ったプロセス間通信について

変更個所は、通信開始の時にサーバー処理のスレッドを複数立ち上げて、別々のクライアントからの受信をそれぞれのスレッドで受ける様にします。 サーバースレッドの終わりでは、スレッドの終了をスレッドの個数分終わった時点で、再度の通信開始のボタンを押下出来る様にしています。
今回のサーバースレッドの起動数は3個に抑えてありますし、スレッドの終了判定などが適当ですので改良の余地はありますが。

サーバー側プログラム

Imports System.Threading
Imports System.IO
Imports System.IO.Pipes

Public Class frmNameServer

    '別スレッドからメッセージを処理するためデリゲートを利用
    Delegate Sub SetRichTextBox1Delegate(ByVal Value As String)
    Private RichTextBox1Delegate As New SetRichTextBox1Delegate(AddressOf _
                                                                AppendTextRichTextBox1)
    'リッチテキストボックスにメッセージを表示する
    Private Sub AppendTextRichTextBox1(ByVal message As String)
        RichTextBox1.AppendText(message)
        RichTextBox1.SelectionStart = RichTextBox1.TextLength
    End Sub

    '別スレッドからボタンの許可設定処理するためデリゲートを利用
    Delegate Sub SetButton1EnabledDelegate(ByVal bln As Boolean)
    Private SetButton1Delegate As New SetButton1EnabledDelegate(AddressOf _
                                                                SetButton1Enabled)
    '[Buttin1]のEnabled設定
    Private Sub SetButton1Enabled(ByVal blnEnabled As Boolean)
        Me.Button1.Enabled = blnEnabled
    End Sub

    'サーバスレッドの数
    Private Const numThreads As Integer = 3
    'サーバスレッド配列
    Private arrServer(numThreads - 1) As Thread
    'サーバスレッド終了フラグ件数
    Private intServerFinish As Integer = 0

    '[Start NamePipe]ボタンクリックイベント
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                     Handles Button1.Click
        intServerFinish = 0
        '名前付きパイプによる通信スレッド開始
        For i = 0 To UBound(arrServer)
            arrServer(i) = New Thread(AddressOf ServerThread)
            arrServer(i).Start()
        Next
        AppendTextRichTextBox1("名前付きパイプ通信待機中・・・" & vbNewLine)

        '[Start NamePipe]ボタン不可設定
        Me.Button1.Enabled = False
    End Sub

    '名前付きパイプによる通信スレッド
    Private Sub ServerThread()
        'サーバー用のパイプを双方向でクライアント数は指定値で生成
        Dim pipeServer As New NamedPipeServerStream("PIPE_TEST", PipeDirection.InOut, numThreads)
        Try
            'パイプスレッド取得
            Dim threadId As Integer = Thread.CurrentThread.ManagedThreadId
            Me.Invoke(RichTextBox1Delegate, _
                      New Object() {"パイプ生成完了(スレッドID:" & threadId & ")" & vbNewLine})

            'パイプの接続を待つ
            pipeServer.WaitForConnection()
            Me.Invoke(RichTextBox1Delegate, New Object() {"パイプ接続完了(スレッドID:" & threadId & ")" & vbNewLine})

            'ストリーム読込を生成
            Dim pipeStreamReader As New StreamReader(pipeServer)
            Try
                While True
                    'パイプからの文字列受信(入力)
                    Dim strRead As String = pipeStreamReader.ReadLine()
                    'ストリームの末尾に到達した場合はNullなので、通信を終了する
                    'If strRead Is Nothing Then
                    If strRead = "" Then
                        Exit While
                    End If
                    '受信文字列の表示
                    Me.Invoke(RichTextBox1Delegate, New Object() {"受信文字列(スレッドID:" & threadId & "):" & strRead & vbNewLine})
                End While

            Catch ex As IOException
                MsgBox(ex.Message)
            Finally
                pipeStreamReader.Close()
            End Try

            'invokeTextBox(dlg, "パイプ通信を終了します。")
            Me.Invoke(RichTextBox1Delegate, New Object() {"パイプ通信の終了" & vbNewLine})

            intServerFinish += 1
            If intServerFinish >= numThreads Then
                '[Button1]の許可設定
                Me.Invoke(SetButton1Delegate, New Object() {True})
            End If

        Catch ex As Exception
            MsgBox(ex.Message)
        Finally
            pipeServer.Close()
        End Try
    End Sub

End Class

クライアント側プログラムは「名前付きパイプを使ったプロセス間通信について」のものと変わっていません。

クライアント側プログラム

Imports System.IO
Imports System.IO.Pipes
Imports System.Security.Principal

Public Class frmNameClient

    '[Start Named Pipe]ボタンクリック時イベント
    Private Sub ButtonSend_Click(sender As Object, e As EventArgs) _
                                                    Handles ButtonSend.Click
        Dim pipeStream As NamedPipeClientStream = Nothing
        Dim pipeSw As StreamWriter = Nothing
        Try
            '[Send Message]ボタンを不可設定
            Me.ButtonSend.Enabled = False
            '名前付きパイプ・クライアント生成
            pipeStream = New NamedPipeClientStream(".", "PIPE_TEST", _
                                                   PipeDirection.InOut, _
                                                   PipeOptions.None, _
                                                   TokenImpersonationLevel.Impersonation)
            '名前付きパイプ接続
            pipeStream.Connect(1000)
            'ストリームライタ
            pipeSw = New StreamWriter(pipeStream)
            pipeSw.AutoFlush = True

            '文字列送信
            pipeSw.WriteLine(Me.TextBox1.Text.Trim)

        Catch ex As Exception
            MsgBox(ex.Message)
        Finally
            'ストリームライタを閉じる
            If Not pipeSw Is Nothing Then
                pipeSw.Close()
            End If
            '名前付きパイプを閉じる
            If Not pipeStream Is Nothing Then
                pipeStream.Close()
            End If
            '[Send Message]ボタンを許可設定
            Me.ButtonSend.Enabled = True
        End Try
    End Sub

End Class
サーバー側のEXEを実行した後、クライアントEXEを3個実行します。 その後、サーバー側の「Start NamePipe」ボタンを押下して、各クライアントの「Start Name Pipe」ボタンを順次押下します。 各クライアント側で送信文字列を入力して「Send Message」ボタンを押下した結果の画像です。

尚、以下は各クライアント側で送信文字列をクリアして「Send Message」ボタンを押下して一連の処理を終了した結果の画像です。

関連する記事

Remoting の IPC を使ったプロセス間通信について
Remoting の IPC を使ったプロセス間通信についてその2(HTTPチャネル)
名前付きパイプを使ったプロセス間通信について
PR

コメント

コメントを書く