NetworkTransport:向服务器和客户端发送多个数据

时间:2017-09-18 03:21:33

标签: c# arrays unity3d networking split

我经历了一个关于如何实现Unity的NetworkTransport的广泛教程,当我跟随时,这一切都很有意义但是一旦我完成并且我开始做出改变,一切都在我身边。我需要一些帮助来了解服务器和客户端脚本之间的关系如何以及如何添加其他变量以发送到服务器/客户端。

从脚本当前的位置开始,我在客户端添加了两个额外的变量(一个Texture2D和一个字符串),这些变量被添加到我的播放器类并传递给服务器和其他客户端。

我已经在客户端脚本中启动了这两个额外的变量添加到我的Player类,并将相同的变量添加到服务器脚本上的ServerClient类。然后在SpawnPlayer函数的客户端脚本中,我传递了这两个额外的变量,但是我对最初如何创建正确的字符串以保存这两个新变量感到困惑。如果有人能指出我正确的方向,那将是非常有帮助的。谢谢!

' NetworkServerController.cs'

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Text;

public class ServerClient
{
    public int connectionID;
    public string playerName;
    public Texture2D animalTex;
    public string animalType;
    public Vector3 position;
}

public class NetworkServerController : MonoBehaviour {

    private const int MAX_CONNECTION = 10;
    private int port = 5701;

    private int hostID;
    private int webHostID;

    private string networkConnections;

    private int reliableChannel;
    private int unreliableChannel;
    private int reliableFragChannel;
    private int unreliableFragChannel;

    private bool isStarted = false;
    private byte error;

    private List<ServerClient> clients = new List<ServerClient>();

    private float lastMovementUpdate;
    private float movementUpdateRate = 0.2f;

    // Onscreen Variables
    private string connectText;
    private string dataText;
    private string clientID;

    private void Awake()
    {
        NetworkServer.Reset();
    }

    private void Start()
    {
        NetworkTransport.Init();
        ConnectionConfig cc = new ConnectionConfig();

        reliableChannel = cc.AddChannel(QosType.Reliable);
        unreliableChannel = cc.AddChannel(QosType.Unreliable);
        reliableFragChannel = cc.AddChannel(QosType.ReliableFragmented);
        unreliableFragChannel = cc.AddChannel(QosType.UnreliableFragmented);

        HostTopology topo = new HostTopology(cc, MAX_CONNECTION);

        hostID = NetworkTransport.AddHost(topo, port);
        Debug.Log("Socket Open. HostID is : " + hostID);

        webHostID = NetworkTransport.AddWebsocketHost(topo, port);
        Debug.Log("Socket Open. webHostID is : " + webHostID);

        isStarted = true;
    }

    int connectionId;

    private void Update()
    {
        if (!isStarted)
        {
            return;
        }
        else if (isStarted)
        {
            // Debug.Log("Server Started.");

            int recHostId;
            int channelId;
            byte[] recBuffer = new byte[1024];
            int bufferSize = 1024;
            int dataSize;
            byte error;
            NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);

            // Network Messenger System
            switch (recData)
            {
                case NetworkEventType.ConnectEvent:    //2
                    Debug.Log("Player " + connectionId + "has connected.");
                    OnConnection(connectionId);
                    break;

                case NetworkEventType.DataEvent:       //3
                    string msg = Encoding.Unicode.GetString(recBuffer, 0, dataSize);
                    Debug.Log("Receiving from " + connectionId + " : " + msg);
                    string[] splitData = msg.Split('|');

                    switch (splitData[0])
                    {
                        case "NAMEIS":
                            OnNameIs(connectionId, splitData[1]);
                            break;

                        case "MYPOSITION":
                            OnMyPosition(connectionId, float.Parse(splitData[1]), float.Parse(splitData[2]));
                            break;

                        default:
                            Debug.Log("Invalid message : " + msg);
                            break;
                    }

                    break;

                case NetworkEventType.DisconnectEvent: //4
                    Debug.Log("Player " + connectionId + "has disconnected.");
                    OnDisconnection(connectionId);
                    break;
            }

            // Ask player for their position
            if (Time.time - lastMovementUpdate > movementUpdateRate)
            {
                lastMovementUpdate = Time.time;
                string m = "ASKPOSITION|";
                foreach (ServerClient sc in clients)
                    m += sc.connectionID.ToString() + '%' + sc.position.x.ToString() + '%' + sc.position.y.ToString() + '|';
                m = m.Trim('|');

                Send(m, unreliableChannel, clients);
            }
        }       
    }

    private void OnConnection(int cnnID)
    {
        // Add player to list
        ServerClient c = new ServerClient();
        c.connectionID = cnnID;
        c.playerName = "TEMP";
        clients.Add(c);

        // When player joins server, tell ID
        // Request player name and send name of all the other players
        string msg = "ASKNAME|" + cnnID + "|";
        foreach (ServerClient sc in clients)
            msg += sc.playerName + '%' + sc.connectionID + "|";

        msg = msg.Trim('|');

        // ASKNAME|3|DAVE%1|MIKE%2|TEMP%3

        Send(msg, reliableChannel, cnnID);
    }

    private void OnDisconnection(int cnnId)
    {
        // Remove this player from our client list
        clients.Remove(clients.Find(x => x.connectionID == cnnId));

        // Tell everyone that someone has disconnected
        Send("DC|" + cnnId, reliableChannel, clients);
    }

    private void OnNameIs(int cnnID, string playerName)
    {
        // Link name to connection ID
        clients.Find(x => x.connectionID == cnnID).playerName = playerName;

        // Tell everone that a new player has connected
        Send("CNN|" + playerName + '|' + cnnID, reliableChannel, clients);
    }

    private void OnMyPosition(int cnnId, float x, float y)
    {
        clients.Find(c => c.connectionID == cnnId).position = new Vector3(x, y, 0);
    }

    private void Send(string message, int channelID, int cnnID)
    {
        List<ServerClient> c = new List<ServerClient>();
        c.Add(clients.Find(x => x.connectionID == cnnID));
        Send(message, channelID, c);
    }

    // overload method
    private void Send(string message, int channelID, List<ServerClient> c)
    {
        Debug.Log("Sending : " + message);
        byte[] msg = Encoding.Unicode.GetBytes(message);
        foreach(ServerClient sc in c)
        {
            NetworkTransport.Send(hostID, sc.connectionID, channelID, msg, message.Length * sizeof(char), out error);
        }
    }
}

&#39; NetworkClientController&#39;的.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Text;

public class Player
{
    public string playerName;
    public GameObject avatar;
    public int connectionId;
    public Texture2D animalTex;
    public string animalType;
}

public class NetworkClientController : MonoBehaviour {

    private const int MAX_CONNECTION = 10;
    private int port = 5701;
    private string IPAddress = "192.168.1.160";

    private int hostID;
    private int webHostID;

    private int reliableChannel;
    private int unreliableChannel;
    private int reliableFragChannel;
    private int unreliableFragChannel;

    private int ourClientID;
    private int connectionID;

    private float connectionTime;
    private bool isConnected = false;
    private bool isStarted = false;
    private byte error;

    private string playerName;

    public GameObject playerPrefab;
    public Dictionary<int, Player> players = new Dictionary<int, Player>();

    private void Start()
    {
        // Connect();
    }

    public void Connect()
    {
        // Check player name
        string pName = GameObject.Find("NameInput").GetComponent<InputField>().text;

        if (pName == "")
        {
            Debug.Log("You must enter a name");
            return;
        }

        playerName = pName;

        NetworkTransport.Init();
        ConnectionConfig cc = new ConnectionConfig();

        reliableChannel = cc.AddChannel(QosType.Reliable);
        unreliableChannel = cc.AddChannel(QosType.Unreliable);
        reliableFragChannel = cc.AddChannel(QosType.ReliableFragmented);
        unreliableFragChannel = cc.AddChannel(QosType.UnreliableFragmented);

        HostTopology topo = new HostTopology(cc, MAX_CONNECTION);

        hostID = NetworkTransport.AddHost(topo, port);
        connectionID = NetworkTransport.Connect(hostID, IPAddress, port, 0, out error);

        connectionTime = Time.time;
        isConnected = true;
    }

    private void Update()
    {
        if (!isConnected)
            return;

        int recHostId;
        int connectionId;
        int channelId;
        byte[] recBuffer = new byte[1024];
        int bufferSize = 1024;
        int dataSize;
        byte error;
        NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);

        // Network Messenger System
        switch (recData)
        {
            case NetworkEventType.DataEvent:       //3
                string msg = Encoding.Unicode.GetString(recBuffer, 0, dataSize);
                Debug.Log("Receiving " + msg);
                string[] splitData = msg.Split('|');

                switch (splitData[0])
                {
                    case "ASKNAME":
                        OnAskName(splitData);
                        break;

                    case "ASKPOSITION":
                        OnAskPosition(splitData);
                        break;

                    case "CNN":
                        SpawnPlayer(splitData[1], int.Parse(splitData[2]));
                        break;

                    case "DC":
                        PlayerDisconnected(int.Parse(splitData[1]));
                        break;

                    default:
                        Debug.Log("Invalid message : " + msg);
                        break;
                }
                break;
        }
    }

    private void OnAskName(string[] data)
    {
        // Set local client ID
        ourClientID = int.Parse(data[1]);

        // Send local client name to the server
        Send("NAMEIS|" + playerName, reliableChannel);

        // Create all remote client players
        for(int i = 2; i < data.Length - 1; i++)
        {
            string[] d = data[i].Split('%');
            SpawnPlayer(d[0], int.Parse(d[1]));
        }
    }

    private void OnAskPosition(string[] data)
    {
        if (!isStarted)
            return;

        // Update remote client positions
        for (int i = 1; i < data.Length - 1; i++)
        {
            string[] d = data[i].Split('%');

            // Prevent the server from updating local client
            if (ourClientID != int.Parse(d[0]))
            {
                Vector3 position = Vector3.zero;
                position.x = float.Parse(d[1]);
                position.y = float.Parse(d[2]);
                players[int.Parse(d[0])].avatar.transform.position = position;
            }
        }

        // Send local client position
        Vector3 myPosition = players[ourClientID].avatar.transform.position;
        string m = "MYPOSITION" + myPosition.x.ToString() + '|' + myPosition.y.ToString();
        Send(m, unreliableChannel);
    }

    private void SpawnPlayer(string playerName, int cnnId, Texture2D animalTex, string animalType)
    {
        GameObject go = Instantiate(playerPrefab) as GameObject;

        // Is this ours?
        if (cnnId == ourClientID)
        {
            // Add mobility
            go.AddComponent<PlayerMovement>();

            // Remove Canvas
            GameObject.Find("Canvas").SetActive(false);
            isStarted = true;
        }

        Player p = new Player();
        p.avatar = go;
        p.playerName = playerName;
        p.connectionId = cnnId;
        p.avatar.GetComponentInChildren<TextMesh>().text = playerName;
        p.animalTex = animalTex;
        p.animalType = animalType;
        players.Add(cnnId, p);
    }

    private void PlayerDisconnected(int cnnId)
    {
        Destroy(players[cnnId].avatar);
        players.Remove(cnnId);
    }

    private void Send(string message, int channelID)
    {
        Debug.Log("Sending : " + message);
        byte[] msg = Encoding.Unicode.GetBytes(message);
        NetworkTransport.Send(hostID, connectionID, channelID, msg, message.Length * sizeof(char), out error);
    }
}

1 个答案:

答案 0 :(得分:1)

简单地说,序列化并发送数据然后接收并反序列化它。如果您仍然感到困惑,请阅读以下步骤:

在您的示例中,您要发送* { box-sizing: border-box; } body { padding: 0; margin: 0; } nav { border-bottom: 1px solid #ddd; font-family: 'Roboto'; display: flex; justify-content: space-between; font-weight: 300; } /* nav:after { content: " "; display: block; clear: both; height: 0.01px; } */ .container { display: flex; } .nav-btn { height: 4em; padding: 0em 1em; border-right: 1px solid grey; display: flex; min-width: 100px; justify-content: center; align-items: center; } .no-border { border-right: 0px solid white; } img { height: 60%; } .fa { color: #ccc; } nav .search { height: 4.5em; width: 20em; font-family: 'Roboto'; font-weight: 400; border-style: none; text-indent: 1em; } nav .search:focus { outline-style: none; } nav .btn { font-weight: 400; color: grey; border: 2px solid #aaa; padding: 0.5em 0.7em; letter-spacing: 0.01em; } .b-a-host { white-space: nowrap; } .nav-btn.hoverback:hover { cursor: pointer; background-color: #f8f8f8; } @media (max-width:500px) { nav { flex-direction: column; } }<link href='https://fonts.googleapis.com/css?family=Roboto:300,400' rel='stylesheet' type='text/css'> <nav> <div class='container'> <div class='nav-btn hoverback'> <img src='https://upload.wikimedia.org/wikipedia/commons/6/69/Airbnb_Logo_B%C3%A9lo.svg' /> </div> <div class='nav-btn no-border'> <i class="fa fa-search fa-2x" aria-hidden="true"></i> <input type='text' placeholder='Where to ?' class='search' /> </div> </div> <div class='container'> <div class='nav-btn hoverback'> <div class='btn b-a-host'>Become a Host</div> </div> <div class='nav-btn hoverback'> Help </div> <div class='nav-btn hoverback'> Sign Up </div> <div class='nav-btn hoverback'> Log In </div> </div> </nav>

发送方:

1 。第一步是表示要在类或结构中发送的数据。

您不希望直接向此类添加Texture2D。您需要将其存储为字节数组。此示例使用string来执行此操作。您还可以将其转换为PNG或JPEG字节数组以减小大小。

Texture2D

2 .Serialize要发送的数据:

要发送的数据示例:

Texture2D.GetRawTextureData()

从Texture2D和字符串:

创建结构的新实例
[Serializable]
public class SendStructure
{
    public byte[] texture;
    public string message;

    public SendStructure(Texture2D texture, string message)
    {
        this.texture = texture.GetRawTextureData();
        this.message = message;
    }
}

序列化到内存

Texture2D textureToSend = new Texture2D(4, 4);
string stringToSend = "Hello";

3 。发送到网络

SendStructure sendStructure = new SendStructure(textureToSend, stringToSend);

接收方:

4 。从网络接收

MemoryStream memStream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(memStream, sendStructure);

//Array data to send over network
byte[] serializedStructure = memStream.ToArray();

5 .De-serialize收到的数据:

NetworkTransport.Send(hostID, sc.connectionID, channelID, serializedStructure, serializedStructure.Length, out error);

6 。访问收到的数据:

检索int outHostId; int outConnectionId; int outChannelId; int receivedSize; byte error; //Where to store received data byte[] buffer = new byte[400000]; NetworkEventType evt = NetworkTransport.Receive(out outHostId, out outConnectionId, out outChannelId, buffer, buffer.Length, out receivedSize, out error);

switch (evt)
{
    case NetworkEventType.DataEvent:
        {
            //De-Serialize recevied byte array into memory
            MemoryStream stream = new MemoryStream(buffer, 0, receivedSize);
            IFormatter formatter = new BinaryFormatter();
            stream.Seek(0, SeekOrigin.Begin);

            //Received data now stored as SendStructure
            SendStructure receivedStructure = formatter.Deserialize(stream) as SendStructure;

            break;
        }
}

检索string

string receivedString = receivedStructure.message;