UnitySocket異步通信


Socket 套接字 一個ip和一個端口組成一個Socket 屬C/S架構 具有長連接和實時性(強聯網) 客戶端服務端都用Socket來聲明 Socket類型又分為多種 常用有Stream流傳輸和Dgram打包傳輸 流傳輸對應協議類型的TCP(傳輸控制協議)Dgram打包傳輸對應協議類型的UDP(用戶數據報協議)
TCP和UDP都是傳輸協議 雙方通信時都需要端口的開放
TCP是可靠的傳輸 收發數據前先建立連接 UDP是不可靠的傳輸 不與對方建立連接 直接把數據報發出去
傳輸端口使用1024-65535
服務端和客戶端都要創建Socket和綁定IP和端口 服務器用Bind綁定和Listen設置監聽數量  通過Accept方法獲取客戶端並用Receive方法接收數據到緩沖區(byte數組) 解析消息頭 switch/case分發執行不同操作 客戶端封裝數據壓入字節流Send發送給已建立連接的服務端
異步(不用線程)Socket通信 定義字典存儲一個ip對應一個Socket  服務端綁定ip和端口 開始連接BeginAccept 生成帶IAsyncResult參數的回調函數 函數中存儲ip對應的Socket 客戶端開始接收數據BeginReceive 函數結束前遞歸調用BeginAccept 模擬線程 接收數據的回調函數中 接收完數據后放入緩沖區字節數組中 轉換為字符串輸出 回調函數結束之前 調用開始接收BeginReceive遞歸調用回調函數 模擬線程;發送消息時 將字符串轉為字節數組用BeginSend開始發送 封裝開始發送的回調函數 函數中輸出向客戶端發送的消息 服務端向所有與自己建立連接的客戶端發消息時 遍歷字典 調用發送消息的函數
客戶端 定義TCPClient 接收隊列和發送隊列 以及字節數組用作緩沖區 首先client開始連接BeginConnect 成功建立連接之后可收發消息 接收消息時使用NetWorkStream開始讀數據BeginRead 封裝讀數據的回調函數 發數據時壓入隊列 並在FixedUpdate中實時監測發送隊列的長度 若壓入數據則開始寫入BeginWrite 發送數據
線程通信實現同步 其實無固定的客戶端與服務端 無論客戶端還是服務端都可收發消息 客戶端有多個 服務端有一個 客戶端發送消息給服務端 服務端接收消息根據switch/case作出處理 再把做完處理的數據廣播發送給所有客戶端做到通信的同步 服務端從BeginAccept開始接收客戶端的連接開始無限調用回調函數 連接之后調用接收數據函數 接收到數據做數據處理完畢的分發函數 服務端有儲存所有客戶端的字典 ip與Socket一一對應 遍歷字典發送消息給所有客戶端BeginSend ;客戶端與服務端有共通之處可提出封裝成一個通用類共同使用 客戶端開始與服務端建立連接用BeginConnect 例如按鈕點擊發送消息 需要綁定點擊事件 在點擊事件的函數中獲取流對象開始寫入數據BeginWrite(即發送消息到服務端)  在與服務端建立連接之后 客戶端開始用BeginRead接收服務端發來的消息 根據switch/case執行服務端發來的指令 並在客戶端渲染出來
///服務端
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System;
public class Server : MonoBehaviour
{
    Socket server;
    EndPoint point;
    byte[] buf;
    string host = "127.0.0.1";
    short port = 8888;
    // Start is called before the first frame update
    void Start()
    {
        server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        point = new IPEndPoint(IPAddress.Parse(host), port);
        server.Bind(point);
        server.Listen(1);
        buf = new byte[1024];
        Debug.Log("wait for connecting");
        server.BeginAccept(AcceptCallBack, server);
    }
    private void AcceptCallBack(IAsyncResult ar)
    {
        Socket server = (Socket)ar.AsyncState;
        Socket client = server.EndAccept(ar);
        Debug.Log(client.RemoteEndPoint.ToString() + "success connect");
        client.BeginReceive(buf, 0, buf.Length, SocketFlags.None, RecvCallBack, client);
        server.BeginAccept(AcceptCallBack, server);
    }
    private void RecvCallBack(IAsyncResult ar)
    {
        Socket client = (Socket)ar.AsyncState;
        int len = client.EndReceive(ar);
        if (len > 0)
        {
            string msg = Encoding.UTF8.GetString(buf, 0, len);
            Debug.Log("receive:" + msg);
            SendMsg(msg, client);
        }
    }
    public void SendMsg(string str,Socket item)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(str);
        item.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallBack, item);
    }
    private void SendCallBack(IAsyncResult ar)
    {
        Socket client = (Socket)ar.AsyncState;
        int len = client.EndSend(ar);
        if (len > 0)
        {
            Debug.Log("成功發送" + len + "字節到客戶端");
        }
    }
    // Update is called once per frame
    void Update()
    {
       
    }
}
///客戶端
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System;
public class Client : MonoBehaviour
{
    TcpClient client;
    string host = "127.0.0.1";
    short port = 8888;
    byte[] buf;
    bool flag = false;
    // Start is called before the first frame update
    void Start()
    {
        client = new TcpClient();
        client.NoDelay = true;
        buf = new byte[1024];
        client.BeginConnect(IPAddress.Parse(host), port, ConnectCallBack, client);
    }
    private void ConnectCallBack(IAsyncResult ar)
    {
        TcpClient client = (TcpClient)ar.AsyncState;
        Debug.Log("success connect server");
        NetworkStream ns = client.GetStream();
        ns.BeginRead(buf, 0, buf.Length, ReadCallBack, ns);
    }
    private void ReadCallBack(IAsyncResult ar)
    {
        NetworkStream ns = (NetworkStream)ar.AsyncState;
        int len = ns.EndRead(ar);
        if (len > 0)
        {
            string msg = Encoding.UTF8.GetString(buf, 0, len);
            Debug.Log("receive server message:"+msg);
            if (msg == "rotate")
            {
                flag = true;
            }
        }
    }
    public void SendMsg(string str)
    {
        byte[] b = Encoding.UTF8.GetBytes(str);
        NetworkStream ns =  client.GetStream();
        ns.BeginWrite(b, 0, b.Length, WriteCallBack, ns);
    }
    private void WriteCallBack(IAsyncResult ar)
    {
        NetworkStream ns = (NetworkStream)ar.AsyncState;
        ns.EndWrite(ar);
    }
    // Update is called once per frame
    void Update()
    {
        if (flag)
        {
            GameObject.Find("Cube2").transform.Rotate(Vector3.up, 5);
        }
    }
}


免責聲明!

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



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