UnityにおけるSocket通信プログラミングの同期実装

10777 ワード


サービス側
サービス側の主な役割は、各クライアントから送信されたデータを処理することであるため、クライアントのSocketプログラミングでは、クライアントの要求をループ処理するために2つのスレッドを使用する必要があり、1つのスレッドはクライアントの接続状況を傍受するために使用され、1つのスレッドはクライアントのメッセージ送信を傍受するために使用される.サービス側がクライアントのメッセージを受信した後、メッセージを処理して各クライアントに配布する必要がある.
基本プロセス
  • ソケット
  • を作成する
  • バインドソケットのIPとポート番号——Bind()
  • ソケットをリスニング状態にしてクライアントの接続要求を待つ--Listen()
  • .
  • 要求が到来すると、要求を受け入れ、このセッションのソケットであるAccept()
  • に戻る.
  • 返されたソケットを使用してクライアントと通信する--Send()/Receive()
  • は戻り、新たな接続要求
  • を再び待つ.
  • ソケット
  • を閉じる
    ​
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    
    namespace TCPLib {
      public class TCPServer {
        private byte[] result = new byte[1024];
    
        private int maxClientCount; //       
        public int MaxClientCount {
          get {
            return maxClientCount;
          }
          set {
            maxClientCount = value;
          }
        }
        //IP  
        private string ip;
        public string IP {
          get {
            return ip;
          }
          set {
            ip = value;
          }
        }
        //   
        private int port;
        public int Port {
          get {
            return port;
          }
          set {
            port = value;
          }
        }
        //     
        private List < Socket > mClientSockets;
        public List < Socket > ClientSockets {
          get {
            return mClientSockets;
          }
        }
        //IP  
        private IPEndPoint iPEndPoint;
    
        //   Socket
        private Socket mServerSocket;
    
        //     Socket
        private Socket mClientSocket;
        public Socket ClientSocket {
          get {
            return mClientSocket;
          }
          set {
            mClientSocket = value;
          }
        }
    
        /// 
        /// 
        /// 
        ///    
        ///        
        public TCPServer(int port, int count) {
          this.ip = IPAddress.Any.ToString();
          this.port = port;
          this.maxClientCount = count;
    
          this.mClientSockets = new List < Socket > ();
          //   IP  
          this.iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
          //      Socket
          this.mServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          //    
          this.mServerSocket.Bind(this.iPEndPoint);
          //      
          this.mServerSocket.Listen(maxClientCount);
        }
    
        /// 
        ///     
        /// 
        /// ip  
        ///    
        ///        
        public TCPServer(string ip, int port, int count) {
          this.ip = ip;
          this.port = port;
          this.maxClientCount = count;
    
          this.mClientSockets = new List < Socket > ();
    
          //   IP  
          this.ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
          //      Socket
          this.mServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          //    
          this.mServerSocket.Bind(this.ipEndPoint);
          //      
          this.mServerSocket.Listen(maxClientCount);
    
        }
    
        public void Start() {
          //       ,              
          var mServerThread = new Thread(this.ListenClientConnect);
          mServerThread.Start();
        }
    
        //       
        private void ListenClientConnect() {
          //       
          bool flag = true;
          while (flag) {
            //           
            this.ClientSocket = this.mServerSocket.Accept();
            //               
            this.mClientSockets.Add(this.ClientSocket);
            this.SendMessage(string.Format("   {0}         ", this.ClientSocket.RemoteEndPoint));
            //         ,            
            var mReceiveThread = new Thread(this.ReceiveClient);
            mReceiveThread.Start(this.ClientSocket);
          }
        }
        //       
        private void ReceiveClient(object obj) {
          //       
          var mClientSocket = (Socket) obj;
          bool flag = true;
          while (flag) {
            try {
              //       
              int receiveLength = mClientSocket.Receive(result);
              //       
              string clientMessage = Encoding.UTF8.GetString(result, 0, receiveLength);
              //                    
              this.SendMessage(string.Format("   {0}    :{1}", mClientSocket.RemoteEndPoint, clientMessage));
            } catch (Exception e) {
              //            
              this.mClientSockets.Remove(mClientSocket);
              this.SendMessage(string.Format("       :   {0}      ,    :{1}", mClientSocket.RemoteEndPoint, e.Message));
              //    
              mClientSocket.Shutdown(SocketShutdown.Both);
              mClientSocket.Close();
              break;
            }
          }
        }
    
        //           
        public void SendMessage(string msg) {
          if (msg == string.Empty || this.mClientSockets.Count <= 0) return;
          foreach(Socket s in this.mClientSockets) {
            (s as Socket).Send(Encoding.UTF8.GetBytes(msg));
          }
        }
    
        /// 
        ///            
        /// 
        /// ip
        /// port
        /// message
        public void SendMessage(string ip, int port, string msg) {
          //         
          IPEndPoint _IPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
          //       
          foreach(Socket s in mClientSockets) {
            if (_IPEndPoint == (IPEndPoint) s.RemoteEndPoint) {
              s.Send(Encoding.UTF8.GetBytes(msg));
            }
          }
        }
      }
    }
    
    
    ​

     
    サービス側の列:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using TCPLib;
    using System.Net;
    using System.Net.Sockets;
    
    namespace TCPLib.Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                //  IP              
                TCPLib.TCPServer s1 = new TCPServer(“127.0.0.1”, 6001, 10);
                //               
                TCPLib.TCPServer s2 = new TCPServer(6001, 10);
    
                //  Start  
                s1.Start();
    
            }
        }
    
    }
    

    クライアント
    クライアントはサービス側と通信するだけでよいため、サービス側と通信する必要があるが、サーバと通信する過程で常に接続をスムーズに保つ必要があるため、接続状況の傍受とメッセージ送信の傍受をそれぞれ処理するために2つのスレッドが必要である.
    基本プロセス
  • サーバのポートと一致するソケットを作成する
  • サーバへの接続要求——Connect()
  • サーバ側との通信-Send()/Receive()
  • ソケット
  • を閉じる
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    
    namespace TCPLib
    {
        public class TCPClient
        {
            private byte[] result = new byte[1024];
    
            /// 
            ///    IP
            /// 
            private string ip;
            public string IP
            {
                get { return ip; }
                set { ip = value; }
            }
            /// 
            ///       
            /// 
            private int port;
            public int Port
            {
                get { return port; }
                set { port = value; }
            }
            /// 
            /// IP  
            /// 
            private IPEndPoint ipEndPoint;
    
            /// 
            ///    Socket
            /// 
            private Socket mClientSocket;
    
            //        
            private bool isConnected = false;
    
            /// 
            /// 
            /// 
            /// IP  
            ///    
            public TCPClient(string ip,int port)
            {
                this.ip = ip;
                this.port = port;
    
                //   IP  
                this.ipEndPoint= new IPEndPoint(IPAddress.Parse(this.ip), this.port);
                //      
                mClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
    
            public void Start()
            {
                //              
                var mConnectThread = new Thread(this.ConnectToServer);
                //    
                mConnectThread.Start();
            }
    
            //     
            private void ConnectToServer()
            {
                while(!isConnected)
                {
                    try
                    {
                        mClientSocket.Connect(this.ipEndPoint);
                        this.isConnected = true;
                    }
                    catch(Exception e)
                    {
                        Console.WriteLine(string.Format("         ,          ,     :{0}", e.Message));
                        this.isConnected = false;
                    }
                    //  5        
                    Thread.Sleep(5000);
                    Console.WriteLine("        ...");
                }
                Console.WriteLine("       ,             ");
    
                //          
                var mReceiveThread = new Thread(this.ReceiveMessage);
                mReceiveThread.Start();
            }
    
            private void ReceiveMessage()
            {
                bool flag = true;
                while(flag)
                {
                    try
                    {
                        //      
                        int receiveLength = this.mClientSocket.Receive(result);
                        //       
                        string serverMessage = Encoding.UTF8.GetString(result, 0, receiveLength);
                        //       
                        Console.WriteLine(serverMessage);
                    }
                    catch(Exception e)
                    {
                        flag = false;
                        //     
                        this.mClientSocket.Shutdown(SocketShutdown.Both);
                        this.mClientSocket.Close();
    
                        //         
                        this.isConnected = false;
                        ConnectToServer();
                    }
                }
            }
    
            private void SendMessage(string msg)
            {
                if (msg == string.Empty || this.mClientSocket == null) return;
    
                mClientSocket.Send(Encoding.UTF8.GetBytes(msg));
            }
        }
    }
    
    

    クライアントの列:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using TCPLib;
    using System.Net;
    using System.Net.Sockets;
     
    namespace TCPLib.Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                //           
                TCPLib.TCPClient c = new TCPClient("127.0.0.1", 6001);
                //  Start  
                c.Start();
                while (true)
                {
                    //          
                    string msg = Console.ReadLine();
                    //        
                    c.SendMessage(msg);
                }
    
            }
        }
    
    }

    まとめ:
    これは基本的な例ですが、この例では現在、以下の問題があります.*ここでは文字列を送信する機能しか実現されていません.このプログラムは、基礎的なint、float、double、string、singleなどのタイプからstructure、class、さらにバイナリファイルのタイプまで、より多くのタイプをサポートする方法がありますか.*この例を拡張するには、すべてのSocketプログラミングプロセスが同じであることがわかります.唯一の違いは、コア機能とカスタム機能を分離できないため、データを受信した後にどのように処理するかです.*今日のこの例では、データ転送のバッファサイズを人為的に1024に設定しています.この設定よりも大きなデータ型に遭遇した場合、この例は変更する必要があります.
    このunityチュートリアルでは、socket同期通信についてこれで終わります.