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

  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中使用Python进行TCP通信,可以通过以下步骤实现: 1. 编写Python脚本实现TCP服务器或客户端功能。 2. 在Unity项目中添加Python脚本,并使用Python.NET库将Python脚本导入到Unity中。 3. 在Unity中调用Python脚本,实现TCP通信功能。 下面是一个简单的示例,演示了如何在Unity中使用Python实现TCP客户端通信: 1. 编写Python脚本 ``` import socket TCP_IP = '127.0.0.1' TCP_PORT = 5005 BUFFER_SIZE = 1024 MESSAGE = "Hello, World!" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) s.send(MESSAGE.encode()) data = s.recv(BUFFER_SIZE) s.close() print("received data:", data.decode()) ``` 这个脚本会连接到一个指定的IP地址和端口,发送一条消息并接收回复。 2. 导入Python脚本到Unity中 在Unity项目中,需要使用Python.NET库将Python脚本导入到C#脚本中。可以从NuGet包管理器中安装Python.NET,也可以手动下载并添加到项目中。 在C#脚本中,可以使用以下代码导入Python脚本: ``` using System; using Python.Runtime; public class PythonClient : MonoBehaviour { void Start() { // Initialize Python runtime PythonEngine.Initialize(); // Import Python script using (Py.GIL()) { dynamic client = Py.Import("tcp_client"); client.main(); } // Shutdown Python runtime PythonEngine.Shutdown(); } } ``` 这个脚本会初始化Python运行时,导入Python脚本并调用其中的`main`函数。 3. 在Unity中调用Python脚本 在需要使用TCP通信的地方,可以使用以下代码调用Python脚本: ``` using System; using Python.Runtime; public class MyComponent : MonoBehaviour { void Start() { using (Py.GIL()) { dynamic client = Py.Import("tcp_client"); client.main(); } } } ``` 这个脚本会在Unity中调用Python脚本的`main`函数,实现TCP通信功能。 需要注意的是,在Unity中使用Python进行TCP通信时,需要确保Python脚本和Unity项目使用的Python版本一致,否则可能会出现错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值