プログラムの概要
Winsock コントロールを使用すると、リモートコンピュータ に接続し、データを交換出来る事を利用して、通信対戦ゲー ムを作成する。 ゲームに関する処理は、既に標準モジュールに、グローバル なプロシージャとして、入力されて居るので、此れを追加し て、使用する(ファイル名はothello_mod.vb で有る)。 相手のアドレス(IPアドレス、又は、コンピュータ名)と 双方のポート(互いに逆に設定)を指定して、設定ボタンを クリックすると、通信が確立し、メッセージ欄の指示に従い ゲームを開始する事が出来る。通信対戦プログラム
C# 2005 ⑥ □ 単純変数の宣言(public、private、データ型 変数名) □ 配列変数の宣言(public、データ型[ ] 配列変数名) □ 標準コントロールの利用(Label、Picture、Group、Button、Text、Radio) □ プロパティの利用(Standard: Text、Checked) □ プロパティの利用(Winsock: CtlState、RemoteHost、RemotePort、LocalIP、e.bytesTotal) □ メソッドの利用(Close、Bind、SendData、GetData、GetBytes、GetString、Dispose) □ イベントの利用(Activated、Click、MouseUp、DataArrival) □ 静的メソッドの利用(Convert.ToInt32、Application.Exit) □ 演算子(代入演算子、算術演算子、比較演算子、結合演算子、論理演算子 !、&&、||) □ 制御構造構文(条件分岐、ループ処理) □ サブルーチン(ジェネラルプロシージャ、引数) □ 標準モジュールの追加(プロジェクト→既存項目の追加→既存のファイル) □ ActiveX コントロールの利用(ツールボックスのカスタマイズ→COM コンポーネント) 今回の課題項目 □ 標準モジュールの利用(共通のコード:Public 変数、Public プロシージャ) □ Winsock コンポーネントの利用(Protocol、RemoteHost、RemotePort、Bind 等) 今回の重点項目 □ 対戦中にオプションボタンをクリック出来ない様にする(Fool Proof)。 □ コンピュータの思考ルーチンを強化する。 □ TCP を利用して一対複数の通信対戦ゲームを考えて見る。 今回の応用項目■ オブジェクト・プロパティ一覧 ■ コントロールの種類 プロパティ プロパティの設定値 フォーム Name othello Text 通信対戦ゲーム オセロ ピクチャーボックス Name picBoard BorderStyle FixedSingle Size 322, 322 BackColor 0, 192, 0 グループ1 Name grpCommunication Text 空白 グループ2 Name grpRival Text 対戦相手 ラジオボタン1 Name radRival0 Text 人間 ラジオボタン2 Name radRival1 Text 電脳 Checked True ラベル1 ラベル2 ボタン2 ボタン1 ピクチャーボックス グループ1 ラベル3 テキスト1 テキスト2 テキスト3 Winsock ラベル7 ラベル8 ラベル9 ラベル6 ラベル4 ラベル5 テキスト4 ボタン3 グループ2 ラジオボタン1 ラジオボタン2
コントロールの種類 プロパティ プロパティの設定値 ラベル1 Name lblTitle Text 通信対戦オセロ Font HG創英角ポップ体、標準、26 ラベル2 Name lblAddressR Text、Font 相手のアドレス(MSゴシック、太字、10) ラベル3 Name lblAddressL Text、Font 自分のアドレス(MSゴシック、太字、10) ラベル4 Name lblPortR Text、Font 相手のポート(MSゴシック、太字、10) ラベル5 Name lblPortL Text、Font 自分のポート(MSゴシック、太字、10) ラベル6 Name lblMessage Text、Font 空白(MSゴシック、太字、12) AutoSize、TextAlign False、MiddleCenter ラベル7 Name lblScore0 Text、Font 0(MSゴシック、太字、16) TextAlign MiddleCenter ForeColor White BackColor Black ラベル8 Name lblScore1 Text、Font 0(MSゴシック、太字、16) TextAlign MiddleCenter ForeColor Black BackColor White ラベル9 Name lblState Text、Font 未受信(MSゴシック、太字、12) AutoSize、TextAlign False、MiddleCenter ForeColor White BackColor Red テキストボックス1 Name txtAddressR Text 192.168.1.1(MSゴシック、太字、10) テキストボックス2 Name txtAddressL Text 192.168.1.2(MSゴシック、太字、10) テキストボックス3 Name txtPortR Text 1001(MSゴシック、太字、10) テキストボックス4 Name txtPortL Text 1002(MSゴシック、太字、10) コマンドボタン1 Name btnSet Text 、Font 設定(MSゴシック,太字,12) コマンドボタン2 Name btnFinish Text 、Font 終了(MSゴシック,太字,12) コマンドボタン3 Name btnPass Text 、Font パス(MSゴシック,太字,12) ソケット Name sckCOM Protocol 1 - sckUDPprotocol
■ 既存標準モジュールの追加 ■ 此処では、UDP プロトコルを用いた双方向通信を主題として居る為、ゲーム部分は、標準モジュール othello_mod.cs に既に入力された物を組み込んで使用する。 標準モジュールをプロジェクトに追加するには、『プロジェクト』メニューより『既存項目の追加』を 選択する。 表示されるダイアログボックスの『ファイルの種類』が『Visual C# ファイル』で有る事を確認した上 で(既定で此の種類が選択されて居る筈で有る)、当該ファイルを指定する。 標準モジュールは、通常、アプリケーションの他のモジュールで共通に使う為の宣言やプロシージャを 記述する為に使用する。
■ プログラムリスト(フォームモジュール部分) ■ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace othello {
public partial class othello : Form {
private bool FirstFlag = false; public othello( ) { InitializeComponent( ); } // フォームがアクティブに成った時の処理
private void othello_Activated( object sender, EventArgs e ) { if ( !FirstFlag ) { // 盤面データの設定 othello_mod.GetData( ); // 盤面の初期化 othello_mod.GameInit( ); othello_mod.TurnDisp( ); othello_mod.BoardInit( ); // 自機の IP アドレスの取得 txtAddressL.Text = sckCOM.LocalIP; // 初回フラグの設定 FirstFlag = true; } } // ボタン(設定)がクリックされた時の処理
private void btnSet_Click( object sender, EventArgs e ) { // ソケットが開いて居る場合はクローズ if ( sckCOM.CtlState != 0 ) sckCOM.Close( ); // リモートホスト(相手)の設定 sckCOM.RemoteHost = txtAddressR.Text; // リモートポート(相手)の設定
sckCOM.RemotePort = System.Convert.ToInt32( txtPortR.Text ); // ローカルポート(自機)に結合
sckCOM.Bind( System.Convert.ToInt32( txtPortL.Text ), txtAddressL.Text ); // 送信 sckCOM.SendData( "OK" ); } データファイルothello.dat は、製作中は、当該プロジェクトの bin/Debug フォルダに、亦、コンパ イル後の実行中は、EXE ファイルと同じフォルダに、格納して置く事。 ネームスペース(名前空間)の使 用を宣言して居る。 此の部分は、エディタが、自動的 に記述して下れる。 クラス名と同じ名前のメソッド は、コンストラクタと呼ばれ、ク ラスのインスタンスを生成し、初 期化するメソッドで有る。 フォームのActivated イベントは 最小化から復帰した時等、アクテ ィブに成る度に発生する為、初期 設定を行う時には注意が必要。 コードモジュールのメソッド(関 数、プロシージャ)を呼び出して 居る。C# では引数が必要無い場 合でも、空の引数リストを括弧で 囲む必要が有る。 LocalIP プロパティで自機のIP アドレスを取得する事が出来る。 RemoteHost プロパティには接続 するコンピュータの名前かIPア ドレスを指定し、RemotePort プ ロパティには接続するポートを指 定する。 Bind メソッドは、ポート番号にコ ントロールに結合して、ローカル ポートを使用出来る様にする。 SendData メソッドは、データを リモートコンピュータに送信する メソッドで有る。
// ボタン(パス)がクリックされた時の処理
private void btnPass_Click( object sender, EventArgs e ) { // パスの処理 othello_mod.PassTurn( ); // 終了判定 if ( !( othello_mod.ed < 0 )) GameOver( ); } // ボタン(終了)がクリックされた時の処理
private void btnFinish_Click( object sender, EventArgs e ) { // ソケットのクローズ sckCOM.Close( ); // プログラムをメモリから消去して終了 this.Dispose( ); Application.Exit( ); } // ピクチャボックス(盤面)でクリックされた時の処理
private void picBoard_MouseUp( object sender, MouseEventArgs e ) {
// 着目座標の算出
othello_mod.cx = e.X / 40; othello_mod.cy = e.Y / 40; // 駒を置く位置を指定 othello_mod.PointPlace( ); // 終了判定 if ( !( othello_mod.ed < 0 )) GameOver(); } // 終了処理を行うジェネラルプロシージャ private void GameOver( )
{ DialogResult k; lblMessage.Text = othello_mod.pr; if ( othello_mod.tn != othello_mod.ed ) { k = MessageBox.Show( "もう一度?", "通信対戦ゲーム", MessageBoxButtons.YesNo ); if ( k == DialogResult.Yes ) { othello_mod.GameInit( ); othello_mod.TurnDisp( ); othello_mod.BoardInit( ); othello_mod.FirstDisp( 0 ); othello_mod.tn = 0;
if ( radRival0.Checked ) sckCOM.SendData( "AGAIN:YES" ); } else { if ( radRival0.Checked ) { sckCOM.SendData( "AGAIN:NO" ); sckCOM.Close( ); } this.Dispose( ); Application.Exit( ); } } } 終了処理は、複数の箇所で必要な のでサブルーチン化して居る。同 じ処理を何度も記述する必要が無 く成り、亦、訂正も1箇所で済む と謂う利点が有る。 アプリケーションを終了する場 合、ソケットは閉じ、正しくプロ グラムをメモリから消去して終了 する事が望ましい。 左右孰れかのマウスボタンを押し た後、開放するとMouseUp イベ ントが発生する。 マウスボタンが押された時のマウ スの当該オブジェクト内での座標 は、引数e 構造体の X と Y に格納 されて居る。 アプリケーションを終了する場 合、ソケットは閉じ、正しくプロ グラムをメモリから消去して終了 する事が望ましい。 Message クラスの Show メソッド では、MsgBox 関数と引数の指定 順序が異なる。
// ソケットが通信データを受信した時の処理
private void sckCOM_DataArrival( object sender,
AxMSWinsockLib.DMSWinsockControlEvents_DataArrivalEvent e ) { string s = ""; object o = ( object ) s; bool d; // 現在のデータブロックの取得
sckCOM.GetData( ref o, ( int ) Microsoft.VisualBasic.VariantType.String, sckCOM.BytesReceived ); s = o.ToString( ); if ( lblState.Text == "未受信" ) { // 接続データの場合の処理 if ( s == "OK" ) { othello_mod.FirstDisp( 0 ); othello_mod.tn = 0; sckCOM.SendData( "RV" ); } else { othello_mod.FirstDisp( 1 ); othello_mod.tn = 1; } } else { // 対戦データの場合の処理 if ( s.Substring( 0, 7 ) == "OTHELLO" ) { if ( s.Substring( 7, 1 ) == "P" ) { othello_mod.PassDisp( ); } else {
othello_mod.cx = System.Convert.ToInt32( s.Substring( 7, 1 )); othello_mod.cy = System.Convert.ToInt32( s.Substring( 8, 1 )); d = othello_mod.JudgePlace( ); othello_mod.ScoreDisp( ); } if ( othello_mod.ed < 0 ) { othello_mod.ba = othello_mod.ba ^ 1; othello_mod.TurnDisp( ); } else { GameOver( ); } }
else if ( s.Substring( 0, 5 ) == "AGAIN" ) { if ( s.Substring( 6 ) == "YES" ) { othello_mod.GameInit( ); othello_mod.TurnDisp( ); othello_mod.BoardInit( ); othello_mod.FirstDisp( 1 ); othello_mod.tn = 1; } else {
sckCOM.Close( ); this.Dispose( ); Application.Exit( ); } } } } } } DataArrival イベントは、新しい データが送信されて来た時に発生 する。 GetData メソッドは、現在のデー タブロック(受信データ)を取得 し、其れを変数に格納する。 送信データの先頭に識別の為の文 字列を付加する事に依り、受信し たデータの種類を判別し易くして 居る。 定義したメソッドは、組込関数と 同様に使用する事が出来る。 C# では、総てのプロシージャで 戻り値を利用する事が出来る。 此の場合の ^ は、ビット演算子 で、1と排他的論理和を取る事に 依り、1は0に、0は1に成る。 此の様に、複数のステートメント をコロン(:)で区切り1行に複 数記述する事も出来る。 条件分岐等が多重にネストして居 る時は、正しくインデントを付け て、対応を明確にして置く事が望 ましい。
Winsock コントロールの Close メソッドに依るソケットのクローズ (再掲) ソケットをクローズするメソッド Object.Close( ) TCP 接続、又は、接続要求を受け付けて居るソケットを閉じる。クライアントアプリケーシ ョンでもサーバーアプリケーションでも使用出来る。 オブジェクトにはWinsock コントロールを指定する。 Winsock コントロールの Bind メソッドに依るポートの結合 ポートを結合するメソッド Object.Bind( 引数1, 引数2 ) UDP 接続に使用するローカルポート、及び、ローカル IP を指定する。 オブジェクトにはWinsock コントロールを指定する。 引数1には、接続に使用するポートを指定し、必ず指定する。 引数2には、接続に使用するローカルインターネットアドレスを指定し、省略する事が出来る。 他のアプリケーションが、当該ポートを使用出来ない様にする時に便利で有る。 Winsock コントロールの LocalIP プロパティに依るローカルマシンの IP アドレスの取得 ローカルマシンのIP アドレスを取得するプロパティ Object.LocalIP ローカルマシンの IP アドレスを、ピリオドで区切られた形式(xxx.xxx.xxx.xxx)の IP ア ドレスで返す。 値の取得而巳可能で有り、設定は出来ない。亦、デザイン時には使用する事が出来ない。 Winsock コントロールの RemoreHost プロパティに依るリモートコンピュータの設定 リモートコンピュータを設定するプロパティ Object.RemoteHost コントロールを送る、又は、データを受信するリモートコンピュータの設定と取得を行う。 ホストネーム(例:FTP://ftp.microsoft.com)を入力する事も、IP アドレス(例:100.0.1.1)を入力す る事も可能で有る。 実行時には、RemoteHost プロパティの変更は、次の接続迄、反映されない。 機 能 書 式 解 説 機 能 書 式 解 説 機 能 書 式 解 説 機 能 書 式 解 説
Winsock コントロールの RemorePort プロパティに依るリモートポート番号の設定 接続するリモートポート番号を設定するプロパティ Object.RemotePort 接続するリモートポート番号の設定と取得を行う。 Protocol プロパティを設定した場合は、RemotePort プロパティは、各プロトコルの適切な既定ポート に自動的に設定される。既定のポート番号は、下記の通りで有る。 指定項目 内容
80 HTTP、WWW(World Wide Web)接続で一般的に使用されて居る。
21 FTP 接続 Winsock コントロールの CtlState プロパティに依る状態の取得 コントロールの状態を表す列挙型の値を返すプロパティ Object.CtlState Winsock の状態を取得する。値の取得而巳可能で、デザイン時には使えない。 エディタのインテリセンスでは表示されないが、MSWinsockLib.StateConstants 列挙体で CtlState プ ロパティが採る値が、定数と仕て定義されて居る。 定数 値 内容 MSWinsockLib.StateConstants.sckClosed 0 閉じて居る(既定値)。 MSWinsockLib.StateConstants.sckOpen 1 開いて居る。 MSWinsockLib.StateConstants.sckListening 2 接続要求を待って居る。 MSWinsockLib.StateConstants.sckConnectionPending 3 接続がペンディング状態で有る。 MSWinsockLib.StateConstants.sckResolvingHost 4 ホストの解決処理中で有る。 MSWinsockLib.StateConstants.sckHostResolved 5 ホストの解決が完了した。 MSWinsockLib.StateConstants.sckConnecting 6 接続処理中で有る。 MSWinsockLib.StateConstants.sckConnected 7 接続が完了した。 MSWinsockLib.StateConstants.sckClosing 8 相手側が接続を閉じ様と仕て居る。 MSWinsockLib.StateConstants.sckError 9 エラーが発生して居る。 猶、バックグラウンド処理でエラーが発生した時(例えば、接続に失敗した時やバックグラウンドで実 行して居る送信や受信に失敗した時等)に発生するError イベントで、発生したエラーの種類を確認す る事も可能で有る。 プログラムと同じフォルダに、素材の標準モジュ ー ル (othello_mod.cs ) と デ ー タ フ ァ イ ル (othello.dat)を格納して置く必要が有る。 機 能 書 式 解 説 機 能 書 式 解 説
Winsock メソッド Accept 送信されて来た接続要求の受入(TCP サーバーアプリケーション而巳) Bind ポートの結合 Close ソケットのクローズ Listen ソケットの作成と接続要求受付モードへの移行(TCP 接続而巳) PeekData データブロックの取得(入力キューからデータを削除しない) SendData データの送信 GetData データブロックの取得(入力キューからデータを削除する) Winsock イベント Close リモートコンピュータが接続を閉じた時に発生 ConnectionRequest リモートコンピュータが接続を要求して来た時に発生 DataArrival 新しいデータが送られて来た時に発生 SendComplete 送信処理が完了した時に発生 SendProgress データの送信中に発生 Error バックグラウンド処理でエラーが発生した時に発生 Connect 接続処理が完了した時に発生 Winsock プロパティ BytesReceived 受信したデータのサイズ LocalHostName ローカルコンピュータのホスト名 LocalIP ローカルコンピュータのIPアドレス LocalPort 接続するローカルポート RemoteHost リモートコンピュータのホスト名(ホスト名、IP アドレスの孰れも可) RemoteHostIP リモートコンピュータの IP アドレス RemotePort 接続するリモートポート
State コントロールの状態(VB.NET 以降では CtlState に変更された) Protocol 使用するプロトコル(TCP か UDP) UDP接続の確立の手順 ピアA側 ピアB側 RemotePort プロパティの設定 RemoteHost プロパティの設定 RemotePort プロパティの設定 Bind メソッドで自ポートと結合 RemoteHost プロパティの設定 通信可能 Bind メソッドで自ポートと結合 通信可能