XNA入門

STEP.03 TCP/IP通信の基礎

このチュートリアルの完成イメージ

完成イメージ@ 完成イメージA

ダウンロード

概要・解説

このチュートリアルではネットワーク通信の基礎部分の理解を深めたいと思います。クライアントには新しいプロジェクトを作成してXNAから送受信のメッセージを送る処理をエミュレートする「ClientEmulator」を作成します。サーバーは Java の Java.nio を使用して I/O の多重化およびノンブロッキングモードで通信します。

Java.nio の扱いは慣れないと分かりづらいと思うので、これから数回に分けて少しずつチュートリアルを進めていきたいと思います。今回はクライアントから接続をする部分を作成します。

用意するもの

ソリューション設定

  • まずはじめに、Visual Studio 2005 Express Edition を起動したらメニューの [ファイル] > [新しいプロジェクト] を選択して新規プロジェクトを作成します。

    ソリューション設定@
  • 上図の 新しいプロジェクト ダイアログが表示されたら プロジェクトの種類(P) から Visual C# を選択して下さい。

  • 次に テンプレート(T) から Windows アプリケーション を選択します。

  • プロジェクト名(N) にプロジェクト名を入力したらOKボタンを押してください。

STEP.03 のソリューション設定は次の図のようになっています。
※プロジェクト作成直後に作成される Form1.csClientEmulator.cs に変更しています。

ソリューション設定A

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();
    }
}

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());
        }
    }
}

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(22327);
            this.chkConnect.MinimumSize = new System.Drawing.Size(570);
            this.chkConnect.Name = "chkConnect";
            this.chkConnect.Size = new System.Drawing.Size(5722);
            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(1215);
            this.lblHost.Name = "lblHost";
            this.lblHost.Size = new System.Drawing.Size(13012);
            this.lblHost.TabIndex = 1;
            this.lblHost.Text = "Host (Name or Address)";
            // 
            // lblPort
            // 
            this.lblPort.AutoSize = true;
            this.lblPort.Location = new System.Drawing.Point(14814);
            this.lblPort.Name = "lblPort";
            this.lblPort.Size = new System.Drawing.Size(2612);
            this.lblPort.TabIndex = 2;
            this.lblPort.Text = "Port";
            // 
            // txtHost
            // 
            this.txtHost.ImeMode = System.Windows.Forms.ImeMode.Disable;
            this.txtHost.Location = new System.Drawing.Point(1430);
            this.txtHost.Name = "txtHost";
            this.txtHost.Size = new System.Drawing.Size(12819);
            this.txtHost.TabIndex = 0;
            this.txtHost.Text = "localhost";
            // 
            // txtPort
            // 
            this.txtPort.ImeMode = System.Windows.Forms.ImeMode.Disable;
            this.txtPort.Location = new System.Drawing.Point(14829);
            this.txtPort.MaxLength = 5;
            this.txtPort.Name = "txtPort";
            this.txtPort.Size = new System.Drawing.Size(4219);
            this.txtPort.TabIndex = 1;
            this.txtPort.Text = "65000";
            // 
            // grpConnected
            // 
            this.grpConnected.Enabled = false;
            this.grpConnected.Location = new System.Drawing.Point(1255);
            this.grpConnected.Name = "grpConnected";
            this.grpConnected.Size = new System.Drawing.Size(268199);
            this.grpConnected.TabIndex = 3;
            this.grpConnected.TabStop = false;
            this.grpConnected.Text = "未接続";
            // 
            // ClientEmulator
            // 
            this.ClientSize = new System.Drawing.Size(292266);
            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 == nullreturn;

            if (tcpClient.Connected == falsereturn;

            // サーバーから切断する
            tcpClient.Close();

            tcpClient = null;
        }
    }
}

更新日 2008/05/31