HOW DO I …
ソケットで通信を行うには
ここでは以下の手順で説明します。 ソケット クライアントを作成する データを送信する データを受信する ソケット クライアントを使用するソケット クライアントを作成する
1. このコンテンツのサポート ファイルの Start フォルダから "UDPClient"プロジェクトを開 きます。 2. クライアントを動作させるため、コンピューターで簡易 TCP/IP サービスを有効にする必 要があります。以下の手順を実行します。 a. コントロール パネルで [プログラムと機能] を開きます。 b. [Windows の機能の有効化または無効化] をクリックします。 c. [Windows の機能] ダイアログで [簡易 TCP/IP サービス] チェック ボックスをオン にして機能を有効にし、[OK] をクリックします。 d. この手順を実行するには、ローカル コンピューターの Administrators グループま たは Network Configuration Operators グループのメンバーとしてログオンする必 要があります。e. コンピューターの [サービス] リストで、"Simple TCP/IP Services" サービスが開始 されていることを確認します。開始されていない場合はサービスを手動で開始し ます。サービスの開始方法の詳細については、「サービスの開始方法を構成する」 を参照してください。 3. メニューから[プロジェクト]→[クラスの追加]”を選択し、SocketClient という名前を付け ます。 4. SocketClient.cs で、System.Net.Sockets、System.Threading、System.Text の名前 空間を追加し、SocketClient クラスに以下のメンバー変数を定義します。 using System.Net.Sockets; using System.Threading; using System.Text;
// このクラスの有効期間中の各呼び出しに使用される、キャッシュされた Socket オブジェクト。 Socket socket = null;
// 非同期処理が完了したことを通知するために信号を送るオブジェクト。
static ManualResetEvent clientDone = new ManualResetEvent(false); // 各非同期呼び出しのタイムアウトをミリ秒で定義する。このタイムアウト期間内に
// 応答を受信しなかった場合、呼び出しが中止される。 const int TIMEOUT_MILLISECONDS = 5000;
// 非同期ソケット メソッドで使用するデータ バッファーの最大サイズ。 const int MAX_BUFFER_SIZE = 2048;
5. 以下のパラメーターを使って socket 変数を初期化するコンストラクターを追加します。 public SocketClient() { // AddressFamily.InterNetwork - ソケットは IP version 4 アドレス指定方式を // 使用してアドレスを解決する。 // SocketType.Dgram - データグラム (メッセージ) パケットをサポートするソケット // PrototcolType.Udp - ユーザー データグラム プロトコル (UDP)
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
6. socket を閉じる Close メソッドを追加します。 public void Close()
{ socket.Close(); }
データを送信する
1. SocketClient.cs で、Send メソッドを追加します。文字列を返すようにし、パラメーター として serverName、portNumber、data を受け入れます。public string Send(string serverName, int portNumber, string data) { } 2. Send メソッドで、string 型の変数 response を定義し、既定値として "Operation Timeout"
を設定します。
string response = "Operation Timeout";
3. ソケットが null でないかどうか確認し、以下のようにデータを送信します。 if (socket != null)
{
// SocketAsyncEventArgs コンテキスト オブジェクトを作成する。 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
// コンテキスト オブジェクトのプロパティを設定する。
socketEventArg.RemoteEndPoint = new DnsEndPoint(serverName, portNumber); // Completed イベントのインライン イベント ハンドラー。 // 注: メソッドを自己完結させるため、このイベント ハンドラーはインラインで実装される。 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { response = e.SocketError.ToString(); // UI スレッドのブロックを解除する。 clientDone.Set(); }); // 送信するデータをバッファーに追加する。
byte[] payload = Encoding.UTF8.GetBytes(data);
socketEventArg.SetBuffer(payload, 0, payload.Length); // イベントの状態をシグナルなしに設定し、スレッドのブロックを発生させる。 clientDone.Reset(); // ソケットを使用して非同期の送信要求を行う。 socket.SendToAsync(socketEventArg); // TIMEOUT_MILLISECONDS の最大秒数まで UI スレッドをブロックする。 // この時間内に応答がなければ、処理を先に進める。 clientDone.WaitOne(TIMEOUT_MILLISECONDS);
} else {
response = "Socket is not initialized"; } 4. 応答を返します。 return response;
データを受信する
1. SocketClient.cs で、Receive メソッドを追加します。文字列を返すようにし、パラメータ ーとして portNumber を受け入れます。public string Receive(int portNumber) { }
2. Receive メソッドで、string 型の変数 response を定義し、既定値として "Operation Timeout" を設定します。
string response = "Operation Timeout";
3. ソケットが null でないかどうか確認し、以下のようにデータを受信します。
if (socket != null) {
// SocketAsyncEventArgs コンテキスト オブジェクトを作成する。 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, portNumber); // データを受信するためのバッファーを設定する。 socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE); // Completed イベントのインライン イベント ハンドラー。 // 注: メソッドを自己完結させるため、このイベント ハンドラーはインラインで実装される。 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) {
// バッファーからデータを取得する。 response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred); response = response.Trim('\0'); } else { response = e.SocketError.ToString(); } clientDone.Set(); }); // イベントの状態をシグナルなしに設定し、スレッドのブロックを発生させる。 clientDone.Reset(); // ソケットを使用して非同期の受信要求を行う。 socket.ReceiveFromAsync(socketEventArg); // TIMEOUT_MILLISECONDS の最大秒数まで UI スレッドをブロックする。 // この時間内に応答がなければ、処理を先に進める。 clientDone.WaitOne(TIMEOUT_MILLISECONDS); } else {
response = "Socket is not initialized"; }
4. 応答を返します。 return response;
ソケット クライアントを使用する
1. MainPage.xaml.cs の、btnEcho の Click イベント ハンドラーで、ClearLog の後に、client と いう名前の新しい SocketClient 変数を作成します。
SocketClient client = new SocketClient();
2. 以下のように、エコーされるメッセージを送信します。
Log(String.Format(">> Sending '{0}' to server ...", txtInput.Text)); string result = client.Send(txtRemoteHost.Text, ECHO_PORT,
txtInput.Text); Log("<< " + result);
Log(">> Requesting receive..."); result = client.Receive(ECHO_PORT); Log("<< " + result);
client.Close();
1. MainPage.xaml.cs の、btnGetQuote の Click イベント ハンドラーで、client という名前の新 しい SocketClient 変数を ClearLog の後に作成します。
SocketClient client = new SocketClient();
2. 以下のように、今日の名言 (quote of the day) の要求を送信します。
// UDP では、着信する UDP メッセージごとにメッセージが送信されるため、"ダミー" メッセージを送信して // 応答を求める。メッセージは空にできないので、以下のメッセージは空白文字 1 つで構成されている。 Log(">> Requesting quote");
string result = client.Send(txtRemoteHost.Text, QOTD_PORT, " "); Log("<< " + result);
3. 以下のように、応答を受信してクライアントを閉じます。 // "今日の名言" (QOTD) を返すサーバーからの応答を受信する。
Log(">> Requesting receive..."); result = client.Receive(QOTD_PORT); Log("<< " + result); client.Close(); 4. プロジェクトを実行します。 5. [Host Name] に利用しているコンピュータ名または現在割り当てられている IP アドレス を入力します。 6. エコーするテキストを追加して [Echo] ボタンをタップします。応答が出力テキスト ボッ クスに返されることを確認します。
7. [Get Quote of the Day] ボタンをタップします。応答が出力テキスト ボックスに返される ことを確認します。
インターネットおよびその他のサービスとのほぼリアルタイムな通信を可能にする、新しいソ ケット機能を紹介しました。
参考ビデオ:
How Do I: Communicate with Sockets in Windows Phone ‘Mango’?