PlayStation Mobile Studio
 PlayStation(R)Mobile SDK 1.21.01

■Playstation Mobile ソケット通信 Prev Top Next
関連ページ:なし


今回はソケット通信をやります。
サンプル見るとソケット通信は C# 標準ライブラリを使用するっポイです。ですので、Playstation Mobileのサンプルとして微妙ではあります。
今回はクライアント側( Playstation Mobile )とサーバー側の2つ作成します。
サーバー側は Microsoft Visual Studio Express 2013 for Windows Desktop で作成します。

アプリケーションについて説明すると、クライアント側で入力した計算式をサーバーに送信し、
サーバー側で四則演算を行い結果をクライアントに返すことをやってます。


●Playstation Mobile側
Common.cs 共通クラスとか
Sprite.vcg バーテックスシェーダーのcgファイル
Sprite.fcg フラグメントシェーダーのcgファイル
Sprite.cs スプライトシェーダークラス
SpriteMesh.cs スプライトメッシュクラス
DebugFont.cs デバッグフォントクラス
SocketClient.cs クライアント側
AppMain.cs main関数があるソースファイル

●サーバー側
SocketServer.cs サーバー側
Form1.cs サーバー側のメインフォーム


---SocketClient.cs---  ↑

using System;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.IO;

public class SocketClient
{
   private TcpClient tcp;

   private string IP;
   private int Port;

   public SocketClient( string ip, int port )
   {
      tcp = null;

      IP = ip;
      Port = port;
   }

   // TcpClientを作成し、サーバーと接続する
   public void Connect()
   {
      tcp = new TcpClient();
      tcp.Connect( IP, Port );
   }

   // データの送信と受信を行う
   public string SendAndRecieve( string data, Encoding enc )
   {
      string result = "";

      // 空電文は送信しない
      if( data.Length > 0 && tcp != null && tcp.Connected == true )
      {
         // NetworkStreamを取得する
         using( NetworkStream ns = tcp.GetStream() )
         {
            // 送信データのバイトデータを作成する
            byte[] sendBytes = enc.GetBytes(data);

            // 送信
            ns.Write(sendBytes, 0, sendBytes.Length);

            using( MemoryStream ms = new MemoryStream() )
            {
               byte[] resBytes = new byte[128];

               int resSize = 0;

               do
               {
                  // データの一部を受信する
                  resSize = ns.Read(resBytes, 0, resBytes.Length);

                  // 受信データなしまたはサーバーが切断した
                  if (resSize == 0)
                      break;

                  // 受信したデータを追加していく
                  ms.Write(resBytes, 0, resSize);
               } while (ns.DataAvailable);

               result = enc.GetString(ms.ToArray());
            }
         }
      }

      return result;
   }

   public void Close()
   {
      if( tcp != null && tcp.Connected )
      {
         tcp.Close();
         tcp = null;
      }
   }
}

クライアントアプリで使用するソケットクラスです。

---AppMain.cs---  ↑


using System;
using System.Collections.Generic;
using System.Net.Sockets;

using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Environment;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.Core.Input;
using System.Text;

namespace PSM_Samples
{
   public class AppMain : IDisposable
   {
      private static GraphicsContext graphics;

      private static DebugFont debugFont;

      // 入力ダイアログ
      private static TextInputDialog dialog;

      // 自作のソケット通信クラス
      private static SocketClient socket;

      private static string formula, result;

      public static void Main (string[] args)
      {
         Initialize ();

         while (true) 
         {
            SystemEvents.CheckEvents ();
            Update ();
            Render ();
         }
      }

      // 初期化
      public static void Initialize ()
      {
         // フレームバッファの解像度はウィンドウの解像度と同じサイズにする
         graphics = new GraphicsContext( 0, 0, PixelFormat.Rgba, PixelFormat.Depth16, MultiSampleMode.None );

         // デバッグフォントの作成
         debugFont = new DebugFont();

         dialog = null;

         // ソケットクラスのインスタンスを作成する
         // 引数はサーバーのIPアドレスとポート番号
         // 今回は同一端末上でクライアントアプリとサーバーアプリを実行するため、IPアドレスは自分自身を指定する
         socket = new SocketClient( "127.0.0.1", 8000 );

         formula = result = "";
      }

      public void Dispose()
      {
         socket.Close();

         if( dialog != null )
            dialog.Dispose();

         debugFont.Dispose();
         graphics.Dispose();
      }

      // フレーム更新
      public static void Update ()
      {
         // GamePadではキーボード入力判定がうまくいかないのでTouchにした

         // タッチすると( シミュレーター上ではマウスクリック )サーバーに接続し、テキスト入力ダイアログを表示する
         List<TouchData> touchData = Touch.GetData(0);
         if( touchData.Count > 0 && touchData[0].Status == TouchStatus.Down )
         {
            try
            {
               formula = result = "";

               // サーバーに接続
               socket.Connect();

               // テキスト入力ダイアログ表示
               dialog = new TextInputDialog();
               dialog.Text = "";
               dialog.Open();

            }catch( Exception )
            {
               result = "Connecting Failed";
               return;
            }
         }

         // テキスト入力ダイアログが表示中
         if (dialog != null )
         {
            // テキスト入力ダイアログが閉じられた
            if( dialog.State == CommonDialogState.Finished)
            {
               // OKが押された
               if (dialog.Result == CommonDialogResult.OK)
               {
                  formula = dialog.Text;

                  try
                  {
                     // サーバーにデータ送信
                     result = socket.SendAndRecieve(formula, Encoding.ASCII);
                  }catch( Exception )
                  {
                     result = "SendAndRecieve Failed";
                     return;
                  }
               }

               // 切断する
               socket.Close();

               // テキスト入力ダイアログを閉じる
               dialog.Dispose();
               dialog = null;
            }
         }
      }

      // レンダリング
      public static void Render()
      {
         // クリア
         graphics.SetClearColor (0.2f, 0.2f, 1, 1 );
         graphics.SetClearDepth( 1 );
         graphics.Clear ();

         // デバッグ情報出力
         debugFont.Draw( graphics, "Touch Window\r" + formula + " = " + result );

         // スワップ
         graphics.SwapBuffers();
      }
   }
}

クライアント側のmain関数です。

入力判定は、これまで使用していたボタン入力をやめてタッチ入力に変更しました。
キーボードを押した時の判定は問題ないですが、放した時の判定は正しく行われず、ずっと押されたままとなってしまいます。
たぶんイベント処理で判定していて、テキスト入力ダイアログを表示することでアクティブウィンドウがテキスト入力ダイアログに移ったため
キーボードから放したイベントを正しく検出できないためかと思います。

---SocketServer.cs---  ↑


using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class SocketServer
{
    private TcpListener tcp;
    private TcpClient client;
    private int Port;

    public SocketServer( int port )
    {
        tcp = null;
        client = null;
        Port = port;
    }

    // クライアントからの接続待ち
    public void Accept()
    {
        if (tcp == null)
        {
            tcp = new TcpListener(IPAddress.Any, Port);
            tcp.Start();
        }

        if (client != null)
        {
            client.Close();
            client = null;
        }

        client = tcp.AcceptTcpClient();
    }

    // funcは関数ポインタで受信したデータをもとに送信データを作成する処理を行う
    public void RecieveAndSend(Func<string, string> func, Encoding enc, out string resMsg, out string sendMsg)
    {
        resMsg = sendMsg = "";

        if (client != null)
        {
            using( NetworkStream ns = client.GetStream() )
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    byte[] resBytes = new byte[128];

                    int resSize = 0;

                    do
                    {
                        // データの一部を受信する
                        resSize = ns.Read(resBytes, 0, resBytes.Length);

                        // 受信データなし、またはクライアントが切断
                        if (resSize == 0)
                            break;

                        // 受信したデータを追加する
                        ms.Write(resBytes, 0, resSize);
                    }while (ns.DataAvailable);

                    resMsg = enc.GetString(ms.ToArray());

                    // 受信データをもとに送信データを作成する
                    sendMsg = func(resMsg);

                    if (sendMsg.Length > 0)
                    {
                       // 送信データのバイトデータを取得する
                       byte[] sendBytes = enc.GetBytes(sendMsg);

                       // 送信
                       ns.Write(sendBytes, 0, sendBytes.Length);
                    }
                }
            }
        }
    }

    public void Close()
    {
        if (client != null)
        {
            client.Close();
            client = null;
        }

        if (tcp != null)
        {
            tcp = null;
        }
    }
}

---Form1.cs---  ↑


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sample09_Server
{
    public partial class Form1 : Form
    {
        SocketServer socket = null;

        public Form1()
        {
            InitializeComponent();

            socket = new SocketServer(8000);
        }

        delegate void SetMessageDelegate( string message );

        private void SetMessage( string message )
        {
            Lbl_Msg.Text = message;
        }

        private void RecieveAndSend()
        {
            while (true)
            {
                try
                {
                    string resMsg, sendMsg;

                    socket.Accept();
                    socket.RecieveAndSend(ResultData, Encoding.ASCII, out resMsg, out sendMsg);
                    Invoke(new SetMessageDelegate(SetMessage), new Object[] { resMsg + " ⇒ " + sendMsg });
                }
                catch (Exception ex)
                {
                    Invoke(new SetMessageDelegate(SetMessage), new Object[] { ex.Message });
                }
            }
        }

        // クライアントからの受信データをもとに四則演算を行いその結果を返す
        // この関数は SocketServer::RecieveAndSend() の関数ポインタとして使用する
        private static string ResultData( string calc )
        {
            if (calc.Length == 0)
                return "";

            List<string> calcArray = new List<string>();
            string[] ope = new string[4]{ "+", "-", "*", "/"};
            string s = "";

            for (int i=0; i<calc.Length; i++ )
            {
                bool findOpe = false;

                for (int j=0; j<ope.Length; j++ )
                {
                    if( calc.Substring( i, 1 ) == ope[j] )
                    {
                        findOpe = true;
                        break;
                    }
                }

                if (findOpe == false)
                {
                    s += calc.Substring(i, 1);
                    if (i == calc.Length - 1)
                        calcArray.Add(s);
                }
                else
                {
                    calcArray.Add(s);
                    calcArray.Add(calc.Substring(i, 1));
                    s = "";
                }
            }

            int num = 0;
            if( int.TryParse( calcArray[0], out num ) == true )
            {
                for( int i=1; i<calcArray.Count; i+=2 )
                {
                    if( i + 1 < calcArray.Count)
                    {
                        int num1;
                        if( int.TryParse( calcArray[i+1], out num1) == true )
                        {
                            switch( calcArray[i] )
                            {
                                case "+":
                                    num += num1;
                                    break;
                                case "-":
                                    num -= num1;
                                    break;
                                case "*":
                                    num *= num1;
                                    break;
                                case "/":
                                    if( num1 != 0 )
                                        num /= num1;
                                    break;
                            }
                        }
                    }
                }
            }

            return num.ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Lbl_Msg.Text = "";

            // 待機ソケットを別スレッドで開始する
            Thread thread = new Thread(new ThreadStart(RecieveAndSend));
            thread.IsBackground = true;
            thread.Start();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            socket.Close();
            socket = null;
        }
    }
}

フォーム上に Lbl_Msg という名称のラベルコントロールを追加してください。


Prev Top Next
inserted by FC2 system