チャット VB 2005 5 プログラムの概要 Winsock コントロールを使用すると リモートコンピュータに接続し データを交換出来る事を利用して チャット ( 通信雑談システム ) を作成する サーバー クライアント共に 背景色が黄色のテキストボックスに必要項目を入力し 設定ボタンをクリックすると 通信が確立し チャットを開始する事が出来る 送信用テキストボックスに送信文を入力して送信ボタンをクリックすると テキストが送信される 送信文 受信文共に 受信用テキストボックスに逐次表示される 猶 通信状況等は 下部のステータスバーに 其の時の状態が表示される 今回の課題項目 単純変数の宣言 (Dim) 標準コントロールの利用 (Label RadioBotton Button Group StatusBar) プロパティの値の取得と設定 (Standard: BackColor Value Caption) プロパティの値の取得と設定 (Winsock: State RemoteHost RemotePort LocalIP 等 ) イベントの利用 (Load Click ConnectionRequest DataArrival) メソッドの利用 (Close Listen Connect Accept SendData GetData SetFocus) ステートメントの利用 (Unload End Exit Sub) 組込関数の利用 (Val RGB DoEvents) 制御構造構文 ( 条件分岐 If ~ Then Else End If ループ処理 Do ~ Loop) 演算子 ( 代入演算子 比較演算子 結合演算子 ) COM コンポーネントの利用 ( ツールボックスのカスタマイズ Winsock) 今回の重点項目 StatusBar コンポーネントの利用 (Panels 等 ) Winsock コンポーネントの利用 (Protocol RemoteHost RemotePort Listen Connect 等 ) 今回の応用項目 送受信文の画面表示を工夫する -1-
ツールボックスのカスタマイズ 今回使用するコントロールの内 Winsock コンポーネントは 標準では ツールボックスには表示されて居ない 標準でツールボックスに表示されて居ないコンポーネントを追加して使用出来る様にする手順は 下記の通りで有る 此処では ツールボックスのコンポーネントに追加すると仕て コンポーネント部を開き 余白部分で右クリックして表示されるポップアップメニューで ツールボックスのカスタマイズ をクリックする 下記のダイアログの COM コンポーネント タブで Microsoft WinSock Control version 6.0 にチェックを入れて OK ボタンをクリックする -2-
オブジェクト プロパティ一覧 グループ 1 ラベル 3 ラベル 4 ラベル 5 Winsock ラベル 1 テキスト 1 テキスト 3 テキスト 5 ラベル 2 グループ 2 ボタン 1 グループ 3 テキスト 2 テキスト 6 グループ 4 テキスト 8 ラジオボタン 1 テキスト 4 テキスト 7 ラジオボタン 2 ボタン 2 ボタン 3 ボタン 4 ステータスバー コントロールの種類 プロパティ プロパティの設定値 フォーム Name chat チャット FormBorderStyle FixedSingle MaximizeBox False グループボックス1 Name grpset Font 設定 (MS 明朝, 太字,10) グループボックス2 Name grpselect 空白 ラジオボタン1 Name radserver サーバー ラジオボタン2 Name radclient クライアント Checked True ラベル1 Name lbllocal ローカル ラベル2 Name lblremote リモート -3-
コントロールの種類 プロパティ プロパティの設定値 ラベル3 Name lbladdress アドレス ラベル4 Name lblport ポート ラベル5 Name lblname 名前 テキストボックス1 Name txtaddressl 192.168.1.1 テキストボックス2 Name txtaddressr 192.168.1.2 テキストボックス3 Name txtportl 1001 テキストボックス4 Name txtportr 1002 テキストボックス5 Name txtnamel 空白 テキストボックス6 Name txtnamer 空白 ボタン1 Name btnset 設定 グループボックス3 Name grpsx 送信 テキストボックス7 Name txtsx ボタン2 Name btnsend 送信 グループボックス4 Name grprx 受信 テキストボックス8 Name txtrx MultiLine True ScrollBars Both ソケット Name sckcom Protocol 0 - scktcpprotocol ステータスストリップ Name stainfo Items ラベルを3 個追加し 下記の様に設定する Name stastate stadate statime AutoSize False BorderSides All BorderStyle SunkenOuter Align MiddleLeft MiddleCenter Spring True False Width 任意 100 ボタン3 Name btnclear 消去 ボタン4 Name btnfinish 終了 -4-
プログラムリスト Public Class chat ' フォームが読み込まれた時の処理 Private Sub chat_load(byval sender As Object, ByVal e As System.EventArgs) Handles Me.Load ' 自機の IP アドレスと名前の取得 txtaddressl. = sckcom.localip txtnamel. = sckcom.localhostname txtaddressr. = sckcom.localip ' 入力必須項目の指示 txtaddressr.backcolor = Color.FromArgb( 255, 255, 255, 128 ) txtportr.backcolor = Color.FromArgb( 255, 255, 255, 128 ) ' ステータスバーの表示 stastate. = " 未接続 " stadate. = DateString statime. = TimeString LocalIP プロパティで自機の IP アドレスを LocalHostName プロパティで自機の名前を取得する事が出来る クライアント側が設定する必要の有る項目のテキストボックスの背景色を黄色に仕て居る ステータスストリップの各々のラベルに情報を表示する ' ボタン ( 設定 ) がクリックされた時の処理 Private Sub btnset_click(byval sender As System.Object, ByVal e As System.EventArgs) _ Handles btnset.click CtlState プロパティで ソケット ' ソケットが開いて居る場合はクローズ If Not sckcom.ctlstate = 0 Then sckcom.close( ) の様々な状態を取得する事が出来 る (0 は開いて居る状態 ) If radserver.checked Then ' サーバーの場合 Me. = " チャット :TCP サーバー " ' ローカルホスト ( 自分 ) のポート番号の設定 sckcom.localport = Val( txtportl. ) ' ソケットを作成し接続要求受付モードに移行 sckcom.listen( ) ' ステータスの表示 stastate. = " 接続受付中 " Else ' クライアントの場合 Me. = " チャット :TCP クライアント " ' リモートホスト ( 相手 ) のアドレス 名前の設定 sckcom.remotehost = txtaddressr. ' リモートホスト ( 相手 ) のポート番号の設定 sckcom.remoteport = Val( txtportr. ) ' リモートホストへの接続要求 sckcom.connect( ) LocalPort プロパティには自機の使用ポートを指定する Listen メソッドは ソケットを作成し 接続要求を受け付けるモードに移行する RemoteHost プロパティには接続するコンピュータの名前かIPアドレスを指定する RemotePort プロパティには接続するポートを指定する Connect メソッドは リモートコンピュータへ接続を要求する -5-
' ステータスの表示 Do Until sckcom.ctlstate = 7 Application.DoEvents( ) Loop stastate. = " 接続済 " End If 良い ' リモートマシンが接続を要求して来た時の処理 Private Sub sckcom_connectionrequest(byval sender As Object, _ ByVal e As AxMSWinsockLib.DMSWinsockControlEvents_ConnectionRequestEvent) _ Handles sckcom.connectionrequest サーバー側而巳が必要とする処理 ' サーバで無い場合はプロシージャを強制脱出 If Not radserver.checked Then Exit Sub 無限ループに陥ら無い為に Application オブジェクトの DoEvents メソッド プログラム が占有して居る制御をオペレーテ ィングシステムに渡す 此処でタイムアウト処理も行うと なので サーバーで無い場合 直 ちにサブプロシージャを抜ける ' リモートコンピュータの情報の表示 txtaddressr. = sckcom.remotehostip txtportr. = sckcom.remoteport ' ソケットを一旦閉じて新しい接続の受付 If Not sckcom.ctlstate = 0 Then sckcom.close( ) sckcom.accept( e.requestid ) ' ステータスの表示 stastate. = " 接続 -" & sckcom.remotehostip RemoteHostIP プロパティで相手機の IP アドレスを RemotePort プロパティで相手機のポート番号を取得する事が出来る Accept メソッドで 接続要求を許可する アンパサント (&) は文字列を結合する演算子で有る ' ボタン ( 送信 ) がクリックされた時の処理 Private Sub btnsend_click( ByVal sender As Object, ByVal e As System.EventArgs ) _ Handles btnsend.click Dim S Dim B( ) As String As Byte 此処で宣言した変数は宣言したサ ブプロシージャ内でしか値の参照 と設定を行う事が出来ない ' 送信テキストに改行を付加して送信 S = txtnamel. & ">" & txtsx. & vbcrlf B = System..Encoding.Unicode.GetBytes( S ) sckcom.senddata( B ) ' 送信テキストを一覧に表示 txtrx. &= S txtsx. = "" : txtsx.focus( ) vbcrlf はVB 定数で 改行を意味する (vbnewline も可 ) SendData メソッドは データをリモートコンピュータに送信するメソッドで有る ' ボタン ( 消去 ) がクリックされた時の処理 Private Sub btnclear_click( ByVal sender As Object, ByVal e As System.EventArgs ) _ Handles btnclear.click txtrx. = "" -6- MultiLine プロパティが真のテキストボックスは 32K 迄の入力が可能
' ボタン ( 終了 ) がクリックされた時の処理 Private Sub btnfinish_click( ByVal sender As Object, ByVal e As System.EventArgs ) _ Handles btnfinish.click If Not sckcom.ctlstate = 0 Then sckcom.close( ) Me.Dispose( ) : End ' データを受信した時の処理 Private Sub sckcom_dataarrival(byval sender As Object, _ ByVal e As AxMSWinsockLib.DMSWinsockControlEvents_DataArrivalEvent) _ Handles sckcom.dataarrival Dim B(e.bytesTotal) As Byte Dim S As String アプリケーションを終了する場合 ソケットは閉じてから終了する事が望ましい アプリケーションを終了する場合 正しくプログラムをメモリから消去して終了する DataArrival イベントは 新しい データが送信されて来た時に発生 するイベントで有る ' 受信データの取得 sckcom.getdata( B ) S = System..Encoding.Unicode.GetString( B ) GetData メソッドは 現在のデー タブロック ( 受信データ ) を取得 し 其れを変数に格納する ' 受信テキストを一覧に追加 txtrx. &= S ' ラジオボタン ( サーバー ) がクリックされた時の処理 Private Sub radserver_click( ByVal sender As Object, ByVal e As System.EventArgs ) _ Handles radserver.click ' 入力必須項目の指示 txtportl.backcolor = Color.FromArgb( 255, 255, 255, 128 ) txtaddressr.backcolor = Color.FromArgb( 255, 255, 255, 255 ) txtportr.backcolor = Color.FromArgb( 255, 255, 255, 255 ) txtportl.focus( ) TCP 接続で サーバー側が設定 する項目は LocalPort プロパティ 丈で有る ' ラジオボタン ( クライアント ) がクリックされた時の処理 Private Sub radclient_click( ByVal sender As Object, ByVal e As System.EventArgs ) _ Handles radclient.click ' 入力必須項目の指示 txtportl.backcolor = Color.FromArgb( 255, 255, 255, 255 ) txtaddressr.backcolor = Color.FromArgb( 255, 255, 255, 128 ) txtportr.backcolor = Color.FromArgb( 255, 255, 255, 128 ) txtaddressr.focus( ) End Class TCP 接続で クライアント側が設定する項目は RemoteHost プロパティと RemotePort プロパティで有る -7-
Winsock コントロール ネットワークサービスへ簡単にアクセスするを提供するコントロール Winsock コントロールは 実行時の画面には表示されないコントロールで TCP ネットワークサービスと UDP ネットワークサービスへ簡単にアクセスするを提供する クライアントアプリケーションやサーバーアプリケーションを記述するのに プロトコルの詳細を理解したり 低水準の Winsock API 関数を呼び出したりする必要は無い 此のコントロールが提供する各種プロパティを設定し メソッドを呼び出す丈で 簡単にリモートマシンに接続し 送受信両方向のデータ交換を行う事が出来る TCP に関する基本事項 TCP( 伝送制御プロトコル ) を使用すると リモートコンピュータとの接続の確立 及び 管理が可能で有る 接続の両端のコンピュータは 接続を使用して データを互いにストリーム転送する事が出来る クライアントアプリケーションを作成する場合は サーバーコンピュータの名前 又は IP アドレス (RemoteHost プロパティ ) 及び 其のサーバーが 接続要求を受け付けて居るポート (RemotePort プロパティ ) を知る必要が有る 此等の情報を設定した後 Connect メソッドを呼び出す サーバーアプリケーションを作成する場合は 接続要求を受け付けるポート (LocalPort プロパティ ) を設定した後 Listen メソッドを呼び出す クライアントコンピュータが接続を要求すると ConnectionRequest イベントが発生する 接続処理を完了させるには ConnectionRequest イベント内で Accept メソッドを呼び出す 接続が確立した後は 孰れのコンピュータもデータの送受信を行う事が出来る データを送信するには SendData メソッドを呼び出す 亦 データを受信すると DataArrival イベントが発生する データを受け取るには DataArrival イベント内で GetData メソッドを呼び出す UDP に関する基本事項 UDP( ユーザーデータグラムプロトコル ) は コネクションレスプロトコルで有る TCP での操作と異なり コンピュータは接続を確立しない 亦 UDP では 同一のアプリケーションが クライアントに成る事も サーバーにも成る事も出来る データを転送するには 先ず クライアントコンピュータ側のアプリケーションの LocalPort プロパティを設定する 次に サーバーコンピュータ側のアプリケーションで RemoteHost プロパティにクライアントコンピュータのインターネットアドレスを設定し RemotePort プロパティに クライアントコンピュータ側のアプリケーションの LocalPort プロパティと同じ値を設定する 其の後 SendData メソッドを呼び出すと メッセージの送信が開始される サーバーコンピュータ側のアプリケーションで必要な操作は此れ丈で有る 次に クライアントコンピュータの DataArrival イベント内で GetData メソッドを呼び出して 送信されたメッセージを受け取る 参考 : インターネット上で広く使用されて居るハイパーテキスト転送プロトコル (HTTP) 及び ファイル転送プロトコル (FTP) の 2 種のインプリメンテーションを提供するインターネットトランスファ (Inet) コントロールも有る -8-
Winsock コントロールの Close メソッドに依るソケットのクローズ ソケットをクローズするメソッド Object.Close( ) TCP 接続 又は 接続要求を受け付けて居るソケットを閉じる クライアントアプリケーションでもサーバーアプリケーションでも使用出来る オブジェクトには Winsock コントロールを指定する Winsock コントロールの Listen メソッドに依る接続要求の待受 ソケットを作成し 接続要求を受け付けるモードに移行するメソッド Object.Listen( ) TCP 接続に於いてソケットを作成し 接続要求を受け付けるモードに移行して クライアントからの接続要求を待ち受ける 此のメソッドは TCP 接続でしかし無い オブジェクトには Winsock コントロールを指定する 接続要求が送られて来ると ConnectionRequest イベントが発生する 接続を受け入れるには ConnectionRequest イベントのコード内で Accept メソッドを使用する必要が有る Winsock コントロールの Connect メソッドに依る接続の要求 リモートコンピュータへの接続を要求するメソッド Object.Connect( 引数 1, 引数 2 ) TCP 接続を確立する際に リモートコンピュータ ( サーバー側 ) への接続を要求する オブジェクトには Winsock コントロールを指定する 引数 1 には リモートコンピュータの名前を指定し 省略する事が出来る 引数 2 には リモートコンピュータのポートを指定し 省略する事が出来る Winsock コントロールの Accept メソッドに依る接続要求の受入 送られて来た接続要求を受け入れるメソッド Object.Accept( 引数 ) TCP 接続に於いて クライアント側より送られて来た接続要求を受け入れる 此のメソッドは サーバー側の ConnectionRequest イベント内で而巳で使用する事が出来る オブジェクトには Winsock コントロールを指定する 引数 1 には RequestID(ConnectionRequest イベントの引数 ) を指定し 省略する事は出来ない -9-
Winsock コントロールの SendData メソッドに依るデータの送信 データをリモートコンピュータに送信するメソッド Object.SendData( 引数 ) 引数で指定したデータをリモートコンピュータに送信する オブジェクトには Winsock コントロールを指定する 引数には 送信するデータ ( 数値 又は 文字列 ) を指定し 必ず指定する Visual Basic.NET 以降では 文字列データを送信する場合は バイト配列と仕て送信する必要が有り亦 Visual Basic では 文字列は Unicode で格納される為 System..Encoding.Unicode クラスの GetBytes メソッドを用いて 文字列をバイト配列に変換する必要が有る Unicode エンコーディングの文字列をバイト配列に変換して 送信する例を 下記に示す Dim S As String Dim B( ) As Byte S = " 送信データ " & vbcrlf B = System..Encoding.Unicode.GetBytes(S) Winsock.SendData(B) 猶 GetBytes メソッドは 変換の間の状態を維持しない 此のメソッドは 1 回の操作で文字ブロックを完全に変換する為のメソッドで有る Winsock コントロールの GetData メソッドに依るデータの受信 現在のデータブロックを取得し変数に格納するメソッド Object.GetData( 引数 1, 引数 2, 引数 3 ) リモートコンピュータより受信したデータを引数で指定した変数に格納する オブジェクトには Winsock コントロールを指定する 引数 1 には 取得したデータを格納する変数を指定し 必ず指定する 引数 2 には 取得するデータの型を指定し 省略する事が出来る 引数 3 には 取得するデータのサイズを指定し 省略する事が出来る 通常は DataArrival イベント内で イベントの引数で与えられる bytestotal を指定して GetData メソッドを呼び出す 猶 引数 3 に bytestotal より小さい値を指定すると 残りのデータが失われる事を知らせる 10040 番の警告が発生する Visual Basic.NET 以降では 受信データは バイト配列に格納される為 Visual Basic の文字列と仕て扱う為には System..Encoding.Unicode クラスの GetString メソッドを用いて バイト配列を文字列に変換する必要が有る -10-
TCP 接続の確立の手順 サーバー側 クライアント側 LocalPort プロパティの設定 RemoteHost プロパティの設定 Listen メソッドの実行 ( 待受 ) RemotePort プロパティの設定 ConnectionRequest イベント Connect メソッドの実行 ( 接続要求 ) Accept メソッドの実行 ( 受付 ) TCP(Transmission Control Protocol) TCP プロトコルは コネクション型のプロトコルで有り 電話に例える事が出来る ユーザは 接続を確立してから処理を行う必要が有る 亦 一旦接続が確立すると TCP プロトコルでは 接続が持続され 非常に大きなファイル等でもデータの完全性が保証されるが 多くのリソースが使用される UDP(User Datagram Protocol) UDP プロトコルは コネクションレス型のプロトコルで有り メモ伝言に例える事が出来る 1 台のコンピュータから別のコンピュータにメッセージが送られるが 両者は明示的に接続されて居ない 亦 各送信データの最大サイズは ネットワークに依り決まる -11-