ネットワーク VB6 | |
サーバのプログラムでWinsockコントロールは1つの接続要求しか受け付けない。複数の接続要求を受け付けるには、必要な数のコントロールが必要になるので、コントロール配列としてWinsockを用意する。
サーバーの処理
フォームにWinsockコントロールを1つ配置し、Indexプロパティを0に設定してコントロール配列とする。0番のWinsock(実際にはWinsock1(0))で接続要求を受け付け、接続要求があれば、新規のWinsock(Winsock1(1)、1番目)を作成してこれと接続する。
次に、別の接続要求があれば、新規のWinsock(Winsock1(2)、2番目)を作成してこれと接続する。以降、同じように接続要求があれば、新規のWinsockと接続していく。したがって、0番目のWinsockは接続要求の受付だけを担当することになる。
フォームの準備
新規フォームを用意し、プロパティを次のように設定する。
Caption … サーバ、 Height … 3600、 Width … 4800
フォームに次のようなコントロールを配置する。
リスクボックス(List1)
List … 接続先、 Height … 2400、 Left … 120、 Top … 120、 Width … 4455
コマンドボタン(Command1)
Caption … 終 了、 Height … 375、 Left … 3480、 Top … 2640、 Width … 1095
Winsock(Winsock1)
Index … 0
実行時には表示されないので適当な位置に配置する。大きさは固定である(サイズ変更できない)。
・プログラムリスト
グローバル変数
Option Explicit '変数宣言を強制する Dim Word(1, 20) As String '単語登録用 Dim WsockNum As Integer 'Winsockコントロール配列用 Dim CompName(20) As String 'リモートコンピュータ名用
グローバル変数として、前と同じように配列Wordは英単語と日本語訳の登録用として、変数WscokNumはコントロール配列Winsock1の添字用として、配列CompNameは接続要求のあった(リモート)コンピュータ名登録用として、それぞれ(General) (Declarations)にプログラムを書く。とりあえず配列CompNameは21個用意してある。ケースによって増減すると良い。
初期設定
Private Sub Form_Load() WsockNum = 0 'コントロール配列の添字(0番目) Winsock1(0).LocalPort = 1001 '接続用ポート番号設定 Winsock1(0).Listen '接続要求受付 '単語の登録 Word(0, 0) = "english" Word(1, 0) = "英語" Word(0, 1) = "apple" Word(1, 1) = "リンゴ" Word(0, 2) = "japan" Word(1, 2) = "日本" Word(0, 3) = "computer" Word(1, 3) = "コンピュータ" Word(0, 4) = "sun" Word(1, 4) = "太陽" Word(0, 5) = "moon" Word(1, 5) = "月" End Sub
最初に実行されるForm_Loadプロシージャでコントロール配列Winsock1の添字用変数WsockNumを0で初期化する。次に、Winsoc1(0)の接続要求受付用のポート番号を設定し、接続要求を待つ。
さらに、前と同じように単語を登録する。word(0,n)には英単語、word(1,n)には日本語訳を登録する。上のプログラムでは、6個だけ登録している。
接続要求の受付
Private Sub Winsock1_ConnectionRequest(Index As Integer, ByVal requestID As Long) 'コントロール配列0で接続要求あり '0番目のWinsockは接続要求受け付け用で、実際に接続には使用しない。 If Index = 0 Then WsockNum = WsockNum + 1 '添字を加算 '新規にWinsockを追加する Load Winsock1(WsockNum) '新規追加したWinsockのポート番号設定(0とする) Winsock1(WsockNum).LocalPort = 0 '新規追加したWinsockで接続処理をする Winsock1(WsockNum).Accept requestID End If End Sub
複数のクライアントからの接続要求を受け付けるので、Winsoc1が配列になっているだけで、ほとんど前(1対1の接続)と同じである。
念のため、接続要求を受けたWinsock1が0番目であることを確認している(If Index = 0 Then)。
コントロール配列Winsock1の添字用変数WsockNumに1を加算して、新しくWinsock1を追加する。追加には、Load命令を使う。
追加したWinsock1のポート番号を0に設定する。ポート番号を0にすると任意のポート番号が使われる(ポート番号はコンピュータが決めてくれる)。
追加したWinsock1と接続要求のあったコンピュータとの接続処理をし、接続を完了する。
データ受信時の処理
Private Sub Winsock1_DataArrival(Index As Integer, ByVal bytesTotal As Long) '引数Index番目のWinsockからデータを受信 Dim dat As String, ans As String 'データ受信用、送信用 Dim n As Integer Winsock1(Index).GetData dat 'データ受信 'クライアントのコンピュータ名受信 If Left(dat, 2) = "##" Then CompName(Index) = Mid(dat, 3) 'コンピュータ名登録 List1.AddItem CompName(Index), Index 'List1に登録 Exit Sub 'プロシージャを抜け出す End If 'リストに受信データ表示 List1.RemoveItem Index 'リストから削除 List1.AddItem CompName(Index) & "=" & dat, Index 'リストにデータ追加 For n = 0 To 20 If dat = Word(0, n) Then Winsock1(Index).SendData Word(1, n) Exit For End If Next n If n = 21 Then Winsock1(Index).SendData "わかりません" End If End Sub
リストボックス(List1)は、コンボボックス(リッチテキスト試作 Vフォントの設定 参照)のリスト部分だけのコントロールである。データの追加にはAddItemメソッド、データの削除にはRemoveItemメソッドを使う。
ここでは、データの追加で
List1.AddItem コンピュータ名, 番号
の形で使っている。これは、コンピュータ名を指定した番号の位置(リストの行番号と考えればよい。0から始まる。)に追加することを表している。
クライアントが接続を閉じたときの処理
Private Sub Winsock1_Close(Index As Integer) CompName(Index) = "" 'コンピュータ名削除(消去) List1.RemoveItem Index 'リストからも削除 List1.AddItem "", Index '空白を挿入 Winsock1(Index).Close '接続を閉じる End Sub
クライアントが接続を閉じるとサーバのCloseプロシージャが呼び出される。閉じられたクライアントとの接続は引数のIndex番目で行われていたので、配列CompName(Index)を空白に(コンピュータ名を削除)する。
リストに表示されているデータを変更するメソッドはないので、リストのIndex番目を削除してから改めてIndex番目に空白を追加している。
最後に、接続を閉じている。
サーバの終了処理
Private Sub Command1_Click() Dim x As Integer For x = 0 To WsockNum Winsock1(x).Close Next x Unload Me End End Sub
追加したWinsockすべてを削除(閉じる)する。閉じるのは0番からWsockNum番までである。
クライアントの処理
クライアントのプログラムは、前の1対1の接続で作成したものがそのまま使えるので、ここでは省略する。
実行する
複数のクライアントから接続要求を受け付けるプログラムなので、複数のクライアントが必要になる。クライアントの数だけVisualBasicを起動することもできないので、コンパイルして実行ファイルを作成してから実行する。
【課題】エラー処理を入れていないので、実行中に停止するかもしれない。Winsock関係でエラーが発生するとErrorプロシージャが呼び出される(詳しくは、ヘルプを参照のこと)ので、エラー処理も考えてみよう。
Copyright © 2001 Hiroshi Masuda |