您好,登录后才能下订单哦!
这篇文章主要介绍“Unity Sockect怎么实现画面实时传输”,在日常操作中,相信很多人在Unity Sockect怎么实现画面实时传输问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Unity Sockect怎么实现画面实时传输”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
前言
一、Socket通信原理
二、画面传输设计
1.逻辑设计图
2.Unity服务端
3.Unity客户端
4.最终效果
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
Socket是比较常用的一种通信方式。有关介绍可以点击查看Socket通信原理
首先创建一个Unity工程,然后新建Server场景,用于接受数据,展示画面。
然后再场景中创建一个RawImage并设置为全屏。
如图:
然后创建一个脚本,命名为UnityServer,再创建一个UnityServer.cs
在Start函数中创建Socket服务器,并开启一个线程用于接受数据。
这里要注意一点,不能在接受数据线程中处理数据,需要在主线程中进行处理。
因为Unity主线程里面的资源不允许其他线程进行访问。
在Update函数中处理数据,并展示图片。
UnityServer .cs代码如下:
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using UnityEngine; using UnityEngine.UI; public class UnityServer : MonoBehaviour { Socket socket = null; Thread thread = null; byte[] buffer = null; bool receState = true; int readTimes = 0; public RawImage rawImage; private Queue<byte[]> datas; void Start () { buffer = new byte[1024 * 1024 * 10]; // 创建服务器, 以Tcp的方式 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(IPAddress.Parse("192.168.1.87"), 10002); // 开启一个线程, 用于接受数据 thread = new Thread(new ThreadStart(Receive)); thread.Start(); datas = new Queue<byte[]>(); } private void Receive() { while (thread.ThreadState == ThreadState.Running && socket.Connected) { // 接受数据Buffer count是数据的长度 int count = socket.Receive(buffer); if (receState && count > 0) { receState = false; BytesToImage(count, buffer); } } } MemoryStream ms = null; public void BytesToImage(int count, byte[] bytes) { try { ms = new MemoryStream(bytes, 0, count); datas.Enqueue(ms.ToArray()); // 将数据存储在一个队列中,在主线程中解析数据。这是一个多线程的处理。 readTimes++; if (readTimes > 5000) { readTimes = 0; GC.Collect(2); // 达到一定次数的时候,开启GC,释放内存 } } catch { } receState = true; } void Update() { if (datas.Count > 0) { // 处理纹理数据,并显示 Texture2D texture2D = new Texture2D(Screen.width, Screen.height); texture2D.LoadImage(datas.Dequeue()); rawImage.texture = texture2D; } } void OnDestroy() { try { if (socket != null) { socket.Shutdown(SocketShutdown.Both); } } catch { } try { if (thread != null) { thread.Abort(); } } catch { } datas.Clear(); } }
然后在场景中创建一个GameObject,将脚本挂载上,并将创建的RawImage拖拽到Inspector面板上对应的位置。
如图:
然后我们创建一个客户端工程,创建一个Client场景。
选中Main Camera,用Ctrl+D复制一个摄像机,放在Main Camera下面。
设置localPosition 和 localRotation为零。
这个相机的主要作用抓取屏幕渲染纹理。
如图:
然后再创建一个脚本,命名为UnityClient.cs脚本。在Start中开启Socket,然后开启一个线程发送数据。
将其挂载在Main Camera上面,并将渲染摄像机拖拽到相应的位置。
UnityClient.cs代码如下:
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; using UnityEngine; public class UnityClient : MonoBehaviour { public Camera cam; public int port = 10002; RenderTexture cameraView = null; Socket socket = null; Thread thread = null; bool success = true; Dictionary<string, Client> clients = new Dictionary<string, Client>(); Vector3 old_position; // 旧位置 Quaternion old_rotation; // 旧旋转 void Start () { cameraView = new RenderTexture(Screen.width, Screen.height, 24); cameraView.enableRandomWrite = true; cam.targetTexture = cameraView; old_position = transform.position; old_rotation = transform.rotation; // 开启Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.87"), port)); socket.Listen(100); // 开启一个线程发送渲染数据 thread = new Thread(new ThreadStart(OnStart)); thread.Start(); } int isNewAdd = 0; void OnStart() { Debug.Log("Socket创建成功"); while (thread.ThreadState == ThreadState.Running) { Socket _socket = socket.Accept(); if (clients.ContainsKey(_socket.RemoteEndPoint.ToString())) { try { clients[_socket.RemoteEndPoint.ToString()].socket.Shutdown(SocketShutdown.Both); } catch { } clients.Remove(_socket.RemoteEndPoint.ToString()); } Client client = new Client { socket = _socket }; clients.Add(_socket.RemoteEndPoint.ToString(), client); isNewAdd = 1; } } void Update() { if (success && clients.Count > 0) { success = false; SendTexture(); } if (isNewAdd > 0) { isNewAdd = 0; SendTexture(1); } } void OnGUI() { GUI.DrawTexture(new Rect(10, 10, 240, 135), cameraView, ScaleMode.StretchToFill); } void OnApplicationQuit() { try { socket.Shutdown(SocketShutdown.Both); } catch { } try { thread.Abort(); } catch { } } Texture2D screenShot = null; int gc_count = 0; void SendTexture(int isInt = 0) { if ((!old_position.Equals(transform.position) || !old_rotation.Equals(transform.rotation)) || isInt == 1) { if (null == screenShot) { screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); } // 读取屏幕像素进行渲染 RenderTexture.active = cameraView; screenShot.ReadPixels(new Rect(0, 0, cameraView.width, cameraView.height), 0, 0); RenderTexture.active = null; byte[] bytes = screenShot.EncodeToJPG(100); foreach (var val in clients.Values) { try { val.socket.Send(bytes); } catch { if (!val.socket.Connected) { clients.Remove(val.socket.RemoteEndPoint.ToString()); } } } gc_count++; if (gc_count > 5000) { gc_count = 0; GC.Collect(2); } Debug.Log("发送数据:" + (float)bytes.Length / 1024f + "KB"); old_position = cam.transform.position; old_rotation = cam.transform.rotation; } success = true; } void OnDestroy() { try { socket.Shutdown(SocketShutdown.Both); } catch { } try { thread.Abort(); } catch { } } } class Client { public Socket socket = null; }
到此,关于“Unity Sockect怎么实现画面实时传输”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。