Unity实现Tcp通信

项目场景:

一个飞屏项目,两台主机使用tcp协议通信。控制端为服务器,发送控制信号,发送图片;大屏端为客户端,接收控制信号展示内容,接收图片并展示。


问题描述

  1. 只有先打开服务器再打开客户端,才能正确连接通信。
  2. 图片传输过去是乱码,不能正确显示。

原因分析:

  1. tcp脚本通信连接相关逻辑是单次连接,没有考虑周全。
  2. 图片数据很长,客户端接收数据不全。


解决方案:

  1. 客户端脚本《TcpClient》添加连接失败后等待10秒后重试。
  2. 服务器发送图片时先发送图片数据长度再发送图片数据,客户端根据图片数据长度接收完整数据,再根据头字节判定是否是图片。

 代码示例1:

 private async void StartClient()
    {
        if (!isRunning)
        {
            Debug.Log("客户端已停止运行,不再尝试连接");
            return;
        }
        Debug.Log("启动客户端" + ConfigMgr.Instance.baseConfig.IP地址);
        //服务器地址
        IPAddress ip = IPAddress.Parse(ConfigMgr.Instance.baseConfig.IP地址);
        IPEndPoint ipEnd = new IPEndPoint(ip, ConfigMgr.Instance.baseConfig.监听端口);
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        bool connected = await ConnectAsync(clientSocket, ipEnd);
        if (connected)
        {
            clientThread = new Thread(ClientThread);
            clientThread.Start();
        }
        else
        {
            Debug.LogError("连接失败,10秒后重试");
            await Task.Delay(10000); // 等待10秒后重试
            StartClient();
        }
    }

    private Task<bool> ConnectAsync(Socket socket, IPEndPoint endPoint)
    {
        return Task.Run(() =>
        {
            try
            {
                socket.Connect(endPoint);
                return true;
            }
            catch (Exception ex)
            {
                Debug.LogError("连接失败: " + ex.Message);
                return false;
            }
        });
    }

代码示例2:

《TcpClient.cs》

 //接收数据并校验
private byte[] ReceiveDataWithLength(Socket client)
    {
        // 接收数据长度
        byte[] lengthBytes = new byte[sizeof(int)];
        int receivedLength = 0;
        while (receivedLength < lengthBytes.Length)
        {
            int bytesReceived = client.Receive(lengthBytes, receivedLength, lengthBytes.Length - receivedLength, SocketFlags.None);
            if (bytesReceived == 0)
            {
                throw new SocketException(); // 连接可能已关闭
            }
            receivedLength += bytesReceived;
        }

        int dataLength = BitConverter.ToInt32(lengthBytes, 0);

        // 检查数据长度是否合理
        if (dataLength < 0 || dataLength > 1024 * 1024 * 10) // 假设最大数据长度为10MB
        {
            throw new OverflowException("接收到的数据长度不合理");
        }

        // 接收数据
        byte[] data = new byte[dataLength];
        receivedLength = 0;
        while (receivedLength < dataLength)
        {
            int bytesReceived = client.Receive(data, receivedLength, dataLength - receivedLength, SocketFlags.None);
            if (bytesReceived == 0)
            {
                throw new SocketException(); // 连接可能已关闭
            }
            receivedLength += bytesReceived;
        }
        Debug.Log("接收数据: " + dataLength + "," + data);

        return data;
    }

 if (fileHead == "255216" || fileHead == "13780")
        {
            //Debug.Log("是图片");
            return true;
        }
        else
        {
            //Debug.Log("不是图片");
            return false;
        }

《TcpServer.cs》

 // 发送RawImage图片(需要在“纹理导入设置”中使此纹理可读)
    public void SendTexture(RawImage rawImage)
    {
        try
        {
            // 获取RawImage的Texture2D
            Texture2D tex = rawImage.texture as Texture2D;
            if (tex == null)
            {
                Debug.LogError("RawImage的texture不是Texture2D类型");
                return;
            }

            // 获取Texture2D的bytes数据
            //byte[] textureBytes = tex.EncodeToPNG(); 

            // 创建一个新的Texture2D来存储未压缩的纹理数据
            Texture2D uncompressedTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
            uncompressedTex.SetPixels(tex.GetPixels());
            uncompressedTex.Apply();

            // 获取未压缩Texture2D的bytes数据
            byte[] textureBytes = uncompressedTex.EncodeToJPG(); 

            // 将图片数据发送给客户端
            SendDataWithLength(client, textureBytes);
            Debug.Log("图片数据长度: " + textureBytes.Length);
        }
        catch (Exception ex)
        {
            Debug.LogError("发送图片时出错: " + ex.Message + "\n" + ex.StackTrace);
        }
    }

     private void SendDataWithLength(Socket client, byte[] data)
    {
        try
        {
            // 发送数据长度
            byte[] lengthBytes = BitConverter.GetBytes(data.Length);
            client.Send(lengthBytes);

            // 发送数据
            int bytesSent = client.Send(data);
            if (bytesSent == data.Length)
            {
                Debug.Log("服务器发送消息成功");
            }
            else
            {
                Debug.LogError("服务器发送消息失败");
            }
        }
        catch (Exception ex)
        {
            Debug.LogError("发送数据时出错: " + ex.Message + "\n" + ex.StackTrace);
        }
    }

Unity是一款跨平台的游戏引擎,它可以用于开发游戏应用程序。在Unity中,可以使用TCP和UDP协议进行网络通信TCP和UDP是用于通过Internet发送信息的两种协议。TCP(传输控制协议)是一种可靠的协议,它通过建立连接、数据分段、校验和等机制,确保数据正确地从发送端传输到接收端。而UDP(用户数据报协议)是一种不可靠的协议,它没有建立连接的过程,数据被分割成数据报并发送出去,但不保证接收端能够正确接收所有数据。 在Unity中,可以使用Socket接口来实现TCP和UDP的通信。Socket接口是TCP/IP网络的API,它定义了许多函数或例程,用于开发TCP/IP网络上的应用程序。通过使用Socket接口,可以在Unity实现TCP和UDP的服务端和客户端。 要在Unity实现TCP服务端,可以使用Socket类的相关方法来监听客户端的连接,并接收和发送数据。具体的实现可以参考引用中的内容。 要在Unity实现TCP客户端,可以使用Socket类的相关方法来连接服务端,并发送和接收数据。具体的实现可以参考引用中的内容。 要在Unity实现UDP服务端,可以使用Socket类的相关方法来接收和发送数据报。具体的实现可以参考引用中的内容。 要在Unity实现UDP客户端,可以使用Socket类的相关方法来发送和接收数据报。具体的实现可以参考引用中的内容。 综上所述,Unity可以通过使用Socket接口来实现TCP和UDP的通信,具体的实现可以参考引用中的内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值