Unity 網絡編程(Socket)應用


服務器端的整體思路:

1、初始化IP地址和端口號以及套接字等字段;

2、綁定IP啟動服務器,開始監聽消息  socketServer.Listen(10);

3、開啟一個后台線程接受客戶端的連接 socketServer.Accept(),這里需要注意的是服務器端有兩個Socket,一個負責監聽,另一個負責傳輸消息,分工明確;

4、接受客戶端消息  socketMsg.Receive();

5、向客戶端發送消息 Send(bySendArray);

6、當然還應該包括信息顯示方法和系統的退出方法。

 

/***
 * 
 * 
 *  服務器端 
 * 
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System;

public class Server : MonoBehaviour
{
    public InputField InpIPAdress;                              //IP地址
    public InputField InpPort;                                  //端口號
    public InputField InpDisplayInfo;                           //顯示信息
    public InputField InpSendMsg;                               //發送信息
    public Dropdown Dro_IPList;                                 //客戶端的IP列表

    private Socket socketServer;                                //服務端套接字
    private bool IsListionContect = true;                              //是否監聽
    private StringBuilder _strDisplayInfo = new StringBuilder();//追加信息
    private string _CurClientIPValue = string.Empty;            //當前選擇的IP地址
    //保存客戶端通訊的套接字
    private Dictionary<string, Socket> _DicSocket = new Dictionary<string, Socket>();
    //保存DropDown的數據,目的為了刪除節點信息
    private Dictionary<string, Dropdown.OptionData> _DicDropdowm = new Dictionary<string, Dropdown.OptionData>();

    // Start is called before the first frame update
    void Start()
    {
        //控件初始化
        InpIPAdress.text = "127.0.0.1";
        InpPort.text = "1000";
        InpSendMsg.text = string.Empty;
        
        //下拉列表處理
        Dro_IPList.options.Clear();                         //清空列表信息
        //添加一個空節點
        Dropdown.OptionData op = new Dropdown.OptionData();
        op.text = "";
        Dro_IPList.options.Add(op);
    }

    /// <summary>
    /// 退出系統
    /// </summary>
    public void ExitSystem()
    {
        //退出會話Socket

        //退出監聽Socket
        if (socketServer != null)
        {
            try
            {
                socketServer.Shutdown(SocketShutdown.Both);     //關閉連接
            }
            catch (Exception)
            {
                
                throw;
            }
            socketServer.Close();                           //清理資源
        }
        Application.Quit();
    }

    /// <summary>
    /// 獲取當前好友
    /// </summary>
    public void GetCurrentIPInformation()
    {
        //選擇玩家當前列表
        _CurClientIPValue = Dro_IPList.options[Dro_IPList.value].text;
    }

    /// <summary>
    /// 服務端開始監聽
    /// </summary>
    public void EnableServerReady()
    { 
        //需要綁定地址和端口號
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(InpIPAdress.text), Convert.ToInt32(InpPort.text));
        //定義監聽Socket
        socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //綁定
        socketServer.Bind(endPoint);

        //開始socket監聽
        socketServer.Listen(10);
        //顯示內容
        DisplayInfo("服務器端啟動");

        //開啟后台監聽(監聽客戶端連接)
        Thread thClientCon = new Thread(ListionCilentCon);
        thClientCon.IsBackground = true;                    //后台線程
        thClientCon.Name = "thListionClientCon";
        thClientCon.Start();
    }

    /// <summary>
    /// 接聽到客戶端的連接
    /// </summary>
    private void ListionCilentCon()
    {
        Socket socMesgServer = null;                        //會話Socket

        try
        {
            while (IsListionContect)
            {
                //等待接受客戶端連接,此處會“阻斷”當前線程
                socMesgServer = socketServer.Accept();
                //獲取遠程節點信息
                string strClientIPAndPort = socketServer.RemoteEndPoint.ToString();
                //把遠程節點信息添加到DropDown控件中
                Dropdown.OptionData op = new Dropdown.OptionData();
                op.text = strClientIPAndPort;
                Dro_IPList.options.Add(op);
                //把會話Socket添加到集合中(為后面發送信息使用)
                _DicSocket.Add(strClientIPAndPort, socMesgServer);
                //控件顯示,有客戶端連接
                DisplayInfo("有客戶端連接");

                //開啟后台線程,接受客戶端信息
                Thread thClientMsg = new Thread(ReceivMsg);
                thClientMsg.IsBackground = true;
                thClientMsg.Name = "thListionClientMsg";
                thClientMsg.Start(socMesgServer);
            }
        }
        catch (Exception)
        {
            IsListionContect = false;
            //關閉會話Socket
            if (socketServer != null)
            {
                socketServer.Shutdown(SocketShutdown.Both);
                socketServer.Close();
            }
            if (socMesgServer != null)
            {
                socMesgServer.Shutdown(SocketShutdown.Both);
                socMesgServer.Close();
            }
        }
    }

    /// <summary>
    /// 后台線程,接受客戶端信息
    /// </summary>
    /// <param name="sockMsg"></param>
    private void ReceivMsg(object sockMsg)
    {
        Socket socketMsg = sockMsg as Socket;

        try
        {
            while (true)
            {
                //准備接受數據緩存
                byte[] msgAarry = new byte[1024 * 0124];
                //准備接受客戶端發來的套接字信息
                int trueClientMsgLenth = socketMsg.Receive(msgAarry);
                //byte數組轉換為字符串
                string strMsg = System.Text.Encoding.UTF8.GetString(msgAarry, 0, trueClientMsgLenth);
                //顯示接受的客戶端消息內容
                DisplayInfo("客戶端消息:" + strMsg);
            }
        }
        catch (Exception)
        {
        }
        finally
        {
            DisplayInfo("有客戶端斷開連接了:" + socketMsg.RemoteEndPoint.ToString());

            //字典類斷開連接的客戶端消息
            _DicSocket.Remove(socketMsg.RemoteEndPoint.ToString());
            //客戶端列表移除
            if (_DicDropdowm.ContainsKey(socketMsg.RemoteEndPoint.ToString()))
            {
                Dro_IPList.options.Remove(_DicDropdowm[socketMsg.RemoteEndPoint.ToString()]);
            }
            //關閉Socket
            socketMsg.Shutdown(SocketShutdown.Both);
            socketMsg.Close();
        }
    
    }

    //向發送客戶端會話
    public void SendMsg()
    { 
        //參數檢查
        _CurClientIPValue = _CurClientIPValue.Trim();
        if (string.IsNullOrEmpty(_CurClientIPValue))
        {
            DisplayInfo("請選擇要聊天的用戶名稱");
            return;
        }

        //判斷是否與指定的Socket通信
        if (_DicSocket.ContainsKey(_CurClientIPValue))
        {
            //得到發送的消息
            string strSendMsg = InpSendMsg.text;
            strSendMsg = strSendMsg.Trim();

            if (!string.IsNullOrEmpty(strSendMsg))
            {
                //信息轉碼
                byte[] bySendArray = System.Text.Encoding.UTF8.GetBytes(strSendMsg);
                //發送數據
                _DicSocket[_CurClientIPValue].Send(bySendArray);
                //記錄發送數據
                DisplayInfo("發送的數據:" + strSendMsg);

                //控件重置
                InpSendMsg.text = string.Empty;
            }
            else
            {
                DisplayInfo("發送的消息不能為空!");
            }
        }
        else
        {
            DisplayInfo("請選擇合法的聊天用戶!");
        }
    
    }

    /// <summary>
    /// 主顯示控件,顯示消息
    /// </summary>
    /// <param name="str"></param>
    private void DisplayInfo(string str)
    {
        str = str.Trim();
        if (!string.IsNullOrEmpty(str))
        {
            _strDisplayInfo.Append(System.DateTime.Now.ToString());
            _strDisplayInfo.Append("  ");
            _strDisplayInfo.Append(str);
            _strDisplayInfo.Append("\r\n");
            InpDisplayInfo.text = _strDisplayInfo.ToString();
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

客戶端整體思路:

1、初始化IP地址和端口號以及一些顯示信息和套接字;

2、啟動客戶端連接 _SockClient.Connect(endPoint);

3、開啟后台線程監聽客戶端發來的信息 _SockClient.Receive(byMsgArray);

4、客戶端發送數據到服務器  _SockClient.Send(byteArray);

5、當然也應該包括退出系統和顯示信息方法。

 

/***
 * 
 * 
 * 
 *  客戶端 
 * 
 * 
 */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine.UI;

public class Client : MonoBehaviour
{
    public InputField InpIPAdress;                          //IP地址
    public InputField InpPort;                              //端口號
    public InputField InpDisplayInfo;                       //顯示信息
    public InputField InpSendMsg;                           //發送信息

    private Socket _SockClient;                             //客戶端Socket
    private IPEndPoint endPoint;
    private bool _IsSendDataConnection=true;                     //發送數據連接
    private StringBuilder _SbDisplayInfo = new StringBuilder();//控件追加信息

    // Start is called before the first frame update
    void Start()
    {
        InpIPAdress.text = "127.0.0.1";
        InpPort.text = "1000";
    }

    //客戶端退出系統
    public void ExitSystem()
    { 
        //關閉客戶端Socket
        if (_SockClient != null)
        {
            try
            {
                //關閉連接
                _SockClient.Shutdown(SocketShutdown.Both);
            }
            catch
            {
            }
            //清理資源
            _SockClient.Close();
        }

        //退出
        Application.Quit();
   
    }

    //啟動客戶端連接
    public void EnableClientCon()
    { 
        //通訊IP和端口號
        endPoint = new IPEndPoint(IPAddress.Parse(InpIPAdress.text), Convert.ToInt32(InpPort.text));
        //建立客戶端Socket
        _SockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            //建立連接
            _SockClient.Connect(endPoint);
            //啟動線程,監聽服務端返回的消息
            Thread thrListenMsgFromServer = new Thread(ListionMsgFromServer);
            thrListenMsgFromServer.IsBackground = true;
            thrListenMsgFromServer.Name = "thrListenMsgFromServer";
            thrListenMsgFromServer.Start();
        }
        catch (Exception)
        {
            
            throw;
        }
        //控件顯示連接服務端成功
        DisplayInfo("連接服務器成功!");
    
    }

    /// <summary>
    /// 后台線程監聽服務端返回的消息
    /// </summary>
    public void ListionMsgFromServer()
    {
        try
        {
            while (true)
            {
                //開辟消息內存區域
                byte[] byMsgArray = new byte[1024 * 0124];
                //客戶端接受服務器返回的數據
                int intTrueMsgLengh = _SockClient.Receive(byMsgArray);
                //轉化為字符串
                string strMsg = System.Text.Encoding.UTF8.GetString(byMsgArray, 0, intTrueMsgLengh);
                //顯示收到的消息
                DisplayInfo("服務器返回消息:" + strMsg);
            }
        }
        catch
        {
        }
        finally
        {
            DisplayInfo("服務器斷開連接");
            _SockClient.Disconnect(true);
            _SockClient.Close();
        }
    
    }

    //客戶端發送數據到服務器
    public void SendMsg()
    {
        string strSendMsg = InpSendMsg.text;
        if (!string.IsNullOrEmpty(strSendMsg))
        {
            //字節轉化
            byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(strSendMsg);
            //發送
            _SockClient.Send(byteArray);
            //顯示發送內容
            DisplayInfo("我:" + strSendMsg);

            //控件清空
            InpSendMsg.text = string.Empty;
        }
        else
        {
            DisplayInfo("提示:發送信息不能為空!");
        }
    }

    /// <summary>
    /// 主顯示控件,顯示消息
    /// </summary>
    /// <param name="str"></param>
    private void DisplayInfo(string str)
    {
        str = str.Trim();
        if (!string.IsNullOrEmpty(str))
        {
            _SbDisplayInfo.Append(System.DateTime.Now.ToString());
            _SbDisplayInfo.Append("  ");
            _SbDisplayInfo.Append(str);
            _SbDisplayInfo.Append("\r\n");
            InpDisplayInfo.text = _SbDisplayInfo.ToString();
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM