STEP.03 TCP/IP通信の基礎
このチュートリアルの完成イメージ
ダウンロード
- Download Sample2DRPG_STEP03_server.zip
- Download Sample2DRPG_STEP03_client.zip
概要・解説
このチュートリアルではネットワーク通信の基礎部分の理解を深めたいと思います。クライアントには新しいプロジェクトを作成してXNAから送受信のメッセージを送る処理をエミュレートする「ClientEmulator」を作成します。サーバーは Java の Java.nio を使用して I/O の多重化およびノンブロッキングモードで通信します。
Java.nio の扱いは慣れないと分かりづらいと思うので、これから数回に分けて少しずつチュートリアルを進めていきたいと思います。今回はクライアントから接続をする部分を作成します。
用意するもの
-
Java Development Kit (JDK)
(サーバー作成で使用します。動作確認は JDK 5.0 Update 15 で行っています。)
ソリューション設定
まずはじめに、Visual Studio 2005 Express Edition を起動したらメニューの [ファイル] > [新しいプロジェクト] を選択して新規プロジェクトを作成します。
上図の 新しいプロジェクト ダイアログが表示されたら プロジェクトの種類(P) から Visual C# を選択して下さい。
次に テンプレート(T) から Windows アプリケーション を選択します。
プロジェクト名(N) にプロジェクト名を入力したらOKボタンを押してください。
STEP.03 のソリューション設定は次の図のようになっています。
※プロジェクト作成直後に作成される Form1.cs を ClientEmulator.cs に変更しています。
JAVA ソースコード(サーバー)
Server.java
package sample2DRPG;
import java.io.IOException;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
public class Server implements Runnable
{
// デフォルトポート番号
public static final int DEFAULT_PORT = 65000;
// ポート番号
protected int port;
// セレクタ
private Selector selector;
// サーバーソケットチャネル
private ServerSocketChannel serverSocketChannel;
/**
* コンストラクタ
* コンストラクタでポートを指定しなかった場合はデフォルトポート番号(65000)が使用されます。
*/
public Server()
{
port = DEFAULT_PORT;
}
public Server(int port)
{
this.port = port;
}
/**
* メイン処理
*/
public void run()
{
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Startup server [port=" + port + "]");
// ループ処理
while (true) {
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
System.out.println("ACCEPTABLE");
handleAcceptable(key);
it.remove();
}
if (key.isConnectable()) {
System.out.println("CONNECTABLE");
}
if (key.isReadable()) {
System.out.println("READABLE");
}
if (key.isWritable()) {
System.out.println("WRITABLE");
}
}
}
} catch(IOException ioe) {
System.out.println("例外が発生したため終了します。[exception=" + ioe + "]");
}
}
/**
* 接続受入
*/
protected boolean handleAcceptable(SelectionKey key)
{
try {
SocketChannel client = serverSocketChannel.accept();
client.configureBlocking(false);
} catch(IOException ioe) {
System.out.println("例外が発生しました。[exception=" + ioe + "]");
}
return true;
}
/**
* エントリーポイント
* @param argv
* @throws Exception
*/
public static void main(String[] argv) throws Exception
{
Server server = new Server();
server.run();
}
}
import java.io.IOException;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
public class Server implements Runnable
{
// デフォルトポート番号
public static final int DEFAULT_PORT = 65000;
// ポート番号
protected int port;
// セレクタ
private Selector selector;
// サーバーソケットチャネル
private ServerSocketChannel serverSocketChannel;
/**
* コンストラクタ
* コンストラクタでポートを指定しなかった場合はデフォルトポート番号(65000)が使用されます。
*/
public Server()
{
port = DEFAULT_PORT;
}
public Server(int port)
{
this.port = port;
}
/**
* メイン処理
*/
public void run()
{
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Startup server [port=" + port + "]");
// ループ処理
while (true) {
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
System.out.println("ACCEPTABLE");
handleAcceptable(key);
it.remove();
}
if (key.isConnectable()) {
System.out.println("CONNECTABLE");
}
if (key.isReadable()) {
System.out.println("READABLE");
}
if (key.isWritable()) {
System.out.println("WRITABLE");
}
}
}
} catch(IOException ioe) {
System.out.println("例外が発生したため終了します。[exception=" + ioe + "]");
}
}
/**
* 接続受入
*/
protected boolean handleAcceptable(SelectionKey key)
{
try {
SocketChannel client = serverSocketChannel.accept();
client.configureBlocking(false);
} catch(IOException ioe) {
System.out.println("例外が発生しました。[exception=" + ioe + "]");
}
return true;
}
/**
* エントリーポイント
* @param argv
* @throws Exception
*/
public static void main(String[] argv) throws Exception
{
Server server = new Server();
server.run();
}
}
C# ソースコード(クライアント)
Program.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ClientEmulator
{
static class Program
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ClientEmulator());
}
}
}
using System.Collections.Generic;
using System.Windows.Forms;
namespace ClientEmulator
{
static class Program
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ClientEmulator());
}
}
}
ClientEmulator.cs
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace ClientEmulator
{
public class ClientEmulator : Form
{
private TcpClient tcpClient;
private CheckBox chkConnect;
private Label lblHost;
private Label lblPort;
private TextBox txtHost;
private TextBox txtPort;
private GroupBox grpConnected;
public ClientEmulator()
{
InitializeComponent();
}
#region private void InitializeComponent()
private void InitializeComponent()
{
this.chkConnect = new System.Windows.Forms.CheckBox();
this.lblHost = new System.Windows.Forms.Label();
this.lblPort = new System.Windows.Forms.Label();
this.txtHost = new System.Windows.Forms.TextBox();
this.txtPort = new System.Windows.Forms.TextBox();
this.grpConnected = new System.Windows.Forms.GroupBox();
this.SuspendLayout();
//
// chkConnect
//
this.chkConnect.Appearance = System.Windows.Forms.Appearance.Button;
this.chkConnect.AutoSize = true;
this.chkConnect.Location = new System.Drawing.Point(223, 27);
this.chkConnect.MinimumSize = new System.Drawing.Size(57, 0);
this.chkConnect.Name = "chkConnect";
this.chkConnect.Size = new System.Drawing.Size(57, 22);
this.chkConnect.TabIndex = 2;
this.chkConnect.Text = "Connect";
this.chkConnect.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.chkConnect.UseVisualStyleBackColor = true;
this.chkConnect.CheckedChanged += new System.EventHandler(this.chkConnect_CheckedChanged);
//
// lblHost
//
this.lblHost.AutoSize = true;
this.lblHost.Location = new System.Drawing.Point(12, 15);
this.lblHost.Name = "lblHost";
this.lblHost.Size = new System.Drawing.Size(130, 12);
this.lblHost.TabIndex = 1;
this.lblHost.Text = "Host (Name or Address)";
//
// lblPort
//
this.lblPort.AutoSize = true;
this.lblPort.Location = new System.Drawing.Point(148, 14);
this.lblPort.Name = "lblPort";
this.lblPort.Size = new System.Drawing.Size(26, 12);
this.lblPort.TabIndex = 2;
this.lblPort.Text = "Port";
//
// txtHost
//
this.txtHost.ImeMode = System.Windows.Forms.ImeMode.Disable;
this.txtHost.Location = new System.Drawing.Point(14, 30);
this.txtHost.Name = "txtHost";
this.txtHost.Size = new System.Drawing.Size(128, 19);
this.txtHost.TabIndex = 0;
this.txtHost.Text = "localhost";
//
// txtPort
//
this.txtPort.ImeMode = System.Windows.Forms.ImeMode.Disable;
this.txtPort.Location = new System.Drawing.Point(148, 29);
this.txtPort.MaxLength = 5;
this.txtPort.Name = "txtPort";
this.txtPort.Size = new System.Drawing.Size(42, 19);
this.txtPort.TabIndex = 1;
this.txtPort.Text = "65000";
//
// grpConnected
//
this.grpConnected.Enabled = false;
this.grpConnected.Location = new System.Drawing.Point(12, 55);
this.grpConnected.Name = "grpConnected";
this.grpConnected.Size = new System.Drawing.Size(268, 199);
this.grpConnected.TabIndex = 3;
this.grpConnected.TabStop = false;
this.grpConnected.Text = "未接続";
//
// ClientEmulator
//
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.grpConnected);
this.Controls.Add(this.txtPort);
this.Controls.Add(this.txtHost);
this.Controls.Add(this.lblPort);
this.Controls.Add(this.lblHost);
this.Controls.Add(this.chkConnect);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "ClientEmulator";
this.Text = "ClientEmulator";
this.Load += new System.EventHandler(this.ClientEmulator_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
/// <summary>
/// Formロード時の処理
/// </summary>
private void ClientEmulator_Load(object sender, EventArgs e)
{
chkConnect.Select();
}
/// <summary>
/// 接続/切断ボタン押下
/// </summary>
private void chkConnect_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = sender as CheckBox;
bool enable = false;
try
{
if (cb.Checked)
{
// サーバーへ接続
connect();
// ボタンを次の操作の名称に変更
cb.Text = "Close";
// グループタイトル更新
grpConnected.Text = "[" + tcpClient.Client.LocalEndPoint + "] に接続中";
enable = true;
}
else
{
// サーバーから切断
close();
// ボタンを次の操作の名称に変更
cb.Text = "Connect";
// グループタイトル更新
grpConnected.Text = "未接続";
}
// テキストボックスEnable設定
txtHost.Enabled = !enable;
txtPort.Enabled = !enable;
// グループEnable設定
grpConnected.Enabled = enable;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
cb.Checked = !cb.Checked;
}
}
/// <summary>
/// 接続処理
/// </summary>
private void connect()
{
string host = txtHost.Text;
int port = 0;
if (!Int32.TryParse(txtPort.Text, out port))
{
MessageBox.Show("Portには数字を入力してください。");
return;
}
// TCP クライアントを生成
tcpClient = new TcpClient();
// サーバーへ接続する
tcpClient.Connect(host, port);
}
/// <summary>
/// 切断処理
/// </summary>
private void close()
{
if (tcpClient == null) return;
if (tcpClient.Connected == false) return;
// サーバーから切断する
tcpClient.Close();
tcpClient = null;
}
}
}
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace ClientEmulator
{
public class ClientEmulator : Form
{
private TcpClient tcpClient;
private CheckBox chkConnect;
private Label lblHost;
private Label lblPort;
private TextBox txtHost;
private TextBox txtPort;
private GroupBox grpConnected;
public ClientEmulator()
{
InitializeComponent();
}
#region private void InitializeComponent()
private void InitializeComponent()
{
this.chkConnect = new System.Windows.Forms.CheckBox();
this.lblHost = new System.Windows.Forms.Label();
this.lblPort = new System.Windows.Forms.Label();
this.txtHost = new System.Windows.Forms.TextBox();
this.txtPort = new System.Windows.Forms.TextBox();
this.grpConnected = new System.Windows.Forms.GroupBox();
this.SuspendLayout();
//
// chkConnect
//
this.chkConnect.Appearance = System.Windows.Forms.Appearance.Button;
this.chkConnect.AutoSize = true;
this.chkConnect.Location = new System.Drawing.Point(223, 27);
this.chkConnect.MinimumSize = new System.Drawing.Size(57, 0);
this.chkConnect.Name = "chkConnect";
this.chkConnect.Size = new System.Drawing.Size(57, 22);
this.chkConnect.TabIndex = 2;
this.chkConnect.Text = "Connect";
this.chkConnect.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.chkConnect.UseVisualStyleBackColor = true;
this.chkConnect.CheckedChanged += new System.EventHandler(this.chkConnect_CheckedChanged);
//
// lblHost
//
this.lblHost.AutoSize = true;
this.lblHost.Location = new System.Drawing.Point(12, 15);
this.lblHost.Name = "lblHost";
this.lblHost.Size = new System.Drawing.Size(130, 12);
this.lblHost.TabIndex = 1;
this.lblHost.Text = "Host (Name or Address)";
//
// lblPort
//
this.lblPort.AutoSize = true;
this.lblPort.Location = new System.Drawing.Point(148, 14);
this.lblPort.Name = "lblPort";
this.lblPort.Size = new System.Drawing.Size(26, 12);
this.lblPort.TabIndex = 2;
this.lblPort.Text = "Port";
//
// txtHost
//
this.txtHost.ImeMode = System.Windows.Forms.ImeMode.Disable;
this.txtHost.Location = new System.Drawing.Point(14, 30);
this.txtHost.Name = "txtHost";
this.txtHost.Size = new System.Drawing.Size(128, 19);
this.txtHost.TabIndex = 0;
this.txtHost.Text = "localhost";
//
// txtPort
//
this.txtPort.ImeMode = System.Windows.Forms.ImeMode.Disable;
this.txtPort.Location = new System.Drawing.Point(148, 29);
this.txtPort.MaxLength = 5;
this.txtPort.Name = "txtPort";
this.txtPort.Size = new System.Drawing.Size(42, 19);
this.txtPort.TabIndex = 1;
this.txtPort.Text = "65000";
//
// grpConnected
//
this.grpConnected.Enabled = false;
this.grpConnected.Location = new System.Drawing.Point(12, 55);
this.grpConnected.Name = "grpConnected";
this.grpConnected.Size = new System.Drawing.Size(268, 199);
this.grpConnected.TabIndex = 3;
this.grpConnected.TabStop = false;
this.grpConnected.Text = "未接続";
//
// ClientEmulator
//
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.grpConnected);
this.Controls.Add(this.txtPort);
this.Controls.Add(this.txtHost);
this.Controls.Add(this.lblPort);
this.Controls.Add(this.lblHost);
this.Controls.Add(this.chkConnect);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "ClientEmulator";
this.Text = "ClientEmulator";
this.Load += new System.EventHandler(this.ClientEmulator_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
/// <summary>
/// Formロード時の処理
/// </summary>
private void ClientEmulator_Load(object sender, EventArgs e)
{
chkConnect.Select();
}
/// <summary>
/// 接続/切断ボタン押下
/// </summary>
private void chkConnect_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = sender as CheckBox;
bool enable = false;
try
{
if (cb.Checked)
{
// サーバーへ接続
connect();
// ボタンを次の操作の名称に変更
cb.Text = "Close";
// グループタイトル更新
grpConnected.Text = "[" + tcpClient.Client.LocalEndPoint + "] に接続中";
enable = true;
}
else
{
// サーバーから切断
close();
// ボタンを次の操作の名称に変更
cb.Text = "Connect";
// グループタイトル更新
grpConnected.Text = "未接続";
}
// テキストボックスEnable設定
txtHost.Enabled = !enable;
txtPort.Enabled = !enable;
// グループEnable設定
grpConnected.Enabled = enable;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
cb.Checked = !cb.Checked;
}
}
/// <summary>
/// 接続処理
/// </summary>
private void connect()
{
string host = txtHost.Text;
int port = 0;
if (!Int32.TryParse(txtPort.Text, out port))
{
MessageBox.Show("Portには数字を入力してください。");
return;
}
// TCP クライアントを生成
tcpClient = new TcpClient();
// サーバーへ接続する
tcpClient.Connect(host, port);
}
/// <summary>
/// 切断処理
/// </summary>
private void close()
{
if (tcpClient == null) return;
if (tcpClient.Connected == false) return;
// サーバーから切断する
tcpClient.Close();
tcpClient = null;
}
}
}
更新日 2008/05/31