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

猜你喜欢

转载自www.cnblogs.com/PJ-Mr-Zhang/p/11508955.html