Untiy UDP局域网 异步发送图片

同步画面有问题,传图片吧

using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System.Net;
using System;
using System.Threading.Tasks;
using System.Threading;public class UdpNet : MonoBehaviour
{public static UdpNet Instance { get; private set; }/// <summary>/// 默认发送数据最大长度,UDP一次性最大发送长度为65536,也就是64kb/// </summary>const int DEFAULT_SIZE = 60000;public UdpClient udpClient;/// <summary>/// 是否可以发送数据/// </summary>public bool isSend;/// <summary>/// 要发送的数据缓存队列/// </summary>private Queue<NetData> datasBuffer;/// <summary>/// 当前发送的数据/// </summary>private NetData curSendData;/// <summary>/// 数据接收注册方法/// </summary>public UnityAction<byte[]> ReceiveDataAction;/// <summary>/// UDP是否开启/// </summary>public bool IsConnect { get; private set; }/// <summary>/// 数据接收缓存队列/// </summary>public Queue<NetData> receiveBufferQueue;/// <summary>/// 当前接收的缓存数据/// </summary>private NetData curReceiveData;/// <summary>/// 当前发送的数据长度/// </summary> <summary>private int byteLen;/// <summary>/// 当前接收的数据长度/// </summary> <summary>private int receiveLen;public int Port;/// <summary>/// 开启UDP/// </summary>/// <param name="port"></param>public void Init(int port){if (udpClient != null){//Debug.LogWarning("已开启UDP控制端");return;}Port = port;udpClient = new UdpClient(port);datasBuffer = new Queue<NetData>();receiveBufferQueue = new Queue<NetData>();isSend = true;IsConnect = true;ReceiveFile();}/// <summary>/// 关闭UDP/// </summary>void Close(){if (udpClient != null){udpClient.Close();udpClient.Dispose();udpClient = null;IsConnect = false;isSend = false;datasBuffer.Clear();curSendData = null;curReceiveData = null;receiveBufferQueue.Clear();//Debug.Log("UdpNet 已关闭");}}#region Mono方法void Awake(){Instance = this;// Init(Port);}private void Update(){if (!IsConnect){return;}if (isSend && datasBuffer.Count > 0 && curSendData == null){isSend = false;curSendData = datasBuffer.Dequeue();byteLen = 0;int len = curSendData.byteArray.length;if (curSendData.byteArray.length > DEFAULT_SIZE){len = DEFAULT_SIZE;}byteLen += len;byte[] bytes = curSendData.byteArray.Read(len);udpClient.BeginSend(bytes, len, curSendData.iPEndPoint, SendFileAysncCallBack, curSendData);}if (receiveBufferQueue.Count > 0){ReceiveDataAction?.Invoke(receiveBufferQueue.Dequeue().byteArray.bytes);}}void OnDestroy(){Close();}#endregion#region 发送消息public void SendMsg(string msg, string ip, int port){byte[] data = Encoding.UTF8.GetBytes(msg);SendBytes(data, ip, port);}public void SendMsg(string msg, IPEndPoint iPEndPoint){byte[] data = Encoding.UTF8.GetBytes(msg);SendBytes(data, iPEndPoint);}public void SendBytes(byte[] data, string ip, int port){IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);SendBytes(data, iPEndPoint);}public void SendBytes(byte[] data, IPEndPoint iPEndPoint){byte[] bytes = Encode(data);//Debug.Log(bytes.Length);ByteArray byteArray = new ByteArray(bytes);datasBuffer.Enqueue(new NetData(byteArray, iPEndPoint));}private void SendFileAysncCallBack(IAsyncResult ar){try{int count = udpClient.EndSend(ar);if (ar.IsCompleted){curSendData.byteArray.readIdx += count;}else{Debug.Log("发送未成功,重新发送");}if (curSendData.byteArray.length == 0){isSend = true;//Debug.Log("发送完毕,共发送数据: " + byteLen);curSendData = null;return;}int len = curSendData.byteArray.length;if (curSendData.byteArray.length > DEFAULT_SIZE){len = DEFAULT_SIZE;}byte[] bytes;lock (curSendData){bytes = curSendData.byteArray.Read(len);}byteLen += len;//Debug.Log(len);RunThread(bytes, len);}catch (System.Exception e){Debug.LogError(e.Message);Close();return;}}//延迟1毫秒发送已缓解udp无法接收完全的问题async void RunThread(byte[] bytes, int len){await Task.Run(() =>{Thread.Sleep(1);udpClient.BeginSend(bytes, len, curSendData.iPEndPoint, SendFileAysncCallBack, curSendData);});}#endregion#region 接收消息private void ReceiveFile(){udpClient.BeginReceive(ReceiveFileAsyncBackCall, null);}private void ReceiveFileAsyncBackCall(IAsyncResult ar){IPEndPoint remoteIp = null;byte[] data = udpClient.EndReceive(ar, ref remoteIp);receiveLen += data.Length;if (curReceiveData == null){int len = Decode(data, out byte[] conData);curReceiveData = new NetData(new ByteArray(len), remoteIp);// curReceiveData.byteArray.Write(data, 4, data.Length - 4);curReceiveData.byteArray.Write(conData, 0, conData.Length);//Debug.Log($"当前接收数据长度: {receiveLen},总接收数据长度: {receiveLen}, 当前剩余容量: {curReceiveData.byteArray.remain}");}else{int dataLen = data.Length;if (data.Length > curReceiveData.byteArray.remain){dataLen = curReceiveData.byteArray.remain;}curReceiveData.byteArray.Write(data, 0, dataLen);//Debug.Log($"当前接收数据长度: {data.Length},总接收数据长度: {receiveLen}, 当前剩余容量: {curReceiveData.byteArray.remain}");}if (curReceiveData.byteArray.remain == 0){receiveBufferQueue.Enqueue(curReceiveData);//Debug.Log("接收完毕: " + curReceiveData.byteArray.writeIdx);curReceiveData = null;}ReceiveFile();}#endregionprivate static byte[] Encode(byte[] data){byte[] bytes = new byte[data.Length + 4];byte[] byteLen = BitConverter.GetBytes(data.Length);Array.Copy(byteLen, 0, bytes, 0, 4);Array.Copy(data, 0, bytes, 4, data.Length);//Debug.Log(bytes.Length);return bytes;}private static int Decode(byte[] data, out byte[] bytes){byte[] byteLen = new byte[4];Array.Copy(data, 0, byteLen, 0, 4);int len = BitConverter.ToInt32(byteLen);bytes = new byte[data.Length - 4];//Debug.Log("总数据长度: " + (len + 4));//Debug.Log("数据内容长度: " + len);Array.Copy(data, 4, bytes, 0, bytes.Length);return len;}public class NetData{public NetData(ByteArray byteArray, IPEndPoint iPEndPoint){this.byteArray = byteArray;this.iPEndPoint = iPEndPoint;}public ByteArray byteArray;public IPEndPoint iPEndPoint;}
}
using UnityEngine.UI;
using System;[Serializable]
public class ByteArray
{//默认大小const int DEFAULT_SIZE = 4096;//初始大小int initSize = 0;//缓冲区public byte[] bytes;//读写位置public int readIdx = 0;public int writeIdx = 0;//容量private int capacity = 0;//剩余空间public int remain { get { return capacity - writeIdx; } }//数据长度public int length { get { return writeIdx - readIdx; } }//构造函数public ByteArray(int size = DEFAULT_SIZE){bytes = new byte[size];capacity = size;initSize = size;readIdx = 0;writeIdx = 0;}//构造函数public ByteArray(byte[] defaultBytes){bytes = defaultBytes;capacity = defaultBytes.Length;initSize = defaultBytes.Length;readIdx = 0;writeIdx = defaultBytes.Length;}//重设尺寸public void ReSize(int size){if (size < length) return;if (size < initSize) return;int n = 1;while (n < size) n *= 2;capacity = n;byte[] newBytes = new byte[capacity];Array.Copy(bytes, readIdx, newBytes, 0, writeIdx - readIdx);bytes = newBytes;writeIdx = length;readIdx = 0;}//写入数据public int Write(byte[] bs, int offset, int count){// UnityEngine.Debug.Log($"remain: {remain} - bs.Length: {bs.Length} - offset: {offset} - count{count} - bytes.Length: {bytes.Length} - writeIdx: {writeIdx}");if (remain < count){ReSize(length + count);}Array.Copy(bs, offset, bytes, writeIdx, count);writeIdx += count;return count;}//读取数据public int Read(byte[] bs, int offset, int count){count = Math.Min(count, length);Array.Copy(bytes, 0, bs, offset, count);readIdx += count;CheckAndMoveBytes();return count;}//读取数据public byte[] Read(int count){// UnityEngine.Debug.Log($"当前数据长度为 {length},从 {readIdx} 开始读取长度为 {count} 的数据, 剩余数据长度为 {writeIdx - readIdx - count}");byte[] bs = new byte[count];Array.Copy(bytes, readIdx, bs, 0, count);// readIdx += count;return bs;}//检查并移动数据public void CheckAndMoveBytes(){if (length < 8){MoveBytes();}}//移动数据public void MoveBytes(){Array.Copy(bytes, readIdx, bytes, 0, length);writeIdx = length;readIdx = 0;}//读取Int16public Int16 ReadInt16(){if (length < 2) return 0;Int16 ret = BitConverter.ToInt16(bytes, readIdx);readIdx += 2;CheckAndMoveBytes();return ret;}//读取Int32public Int32 ReadInt32(){if (length < 4) return 0;Int32 ret = BitConverter.ToInt32(bytes, readIdx);readIdx += 4;CheckAndMoveBytes();return ret;}//打印缓冲区public override string ToString(){return BitConverter.ToString(bytes, readIdx, length);}//打印调试信息public string Debug(){return string.Format("readIdx({0}) writeIdx({1}) bytes({2})",readIdx,writeIdx,BitConverter.ToString(bytes, 0, capacity));}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
//接收视频画面
public class : MonoBehaviour
{public RawImage rawImage;public int port = 8889;// Start is called before the first frame updatevoid Start(){UdpNet.Instance.Init(port);UdpNet.Instance.ReceiveDataAction += ReceiveDataAction;}private void ReceiveDataAction(byte[] arg0){if (arg0.Length < 1000){Debug.Log(Encoding.UTF8.GetString(arg0));return;}Texture2D texture2D = new Texture2D(10, 10);texture2D.LoadImage(arg0);texture2D.Apply();rawImage.texture = texture2D;Resources.UnloadUnusedAssets();}// Update is called once per framevoid Update(){}
}
using System.Collections;
using System.Collections.Generic;
using System.Net;
using UnityEngine;
using UnityEngine.UI;
//发送视频画面
public class SendWebCameraVideo: MonoBehaviour
{public string deviceName;public WebCamTexture webCam;public RawImage rawImage;public int frames = 30;public string ToIP = "127.0.0.1";public int ToPort = 8889;public int Port = 7777;private IPEndPoint iPEndPoint;public float maxTime;public float timer;public bool send;// Start is called before the first frame updatevoid Start(){UdpNet.Instance.Init(Port);WebCamDevice[] devices = WebCamTexture.devices;deviceName = devices[0].name;RectTransform rawRect = rawImage.GetComponent<RectTransform>();webCam = new WebCamTexture(deviceName, (int)rawRect.sizeDelta.x, (int)rawRect.sizeDelta.y, frames);//设置宽、高和帧率   rawImage.texture = webCam;//渲染脚本所在有RawImage组件的物体maxTime = 1f / frames;iPEndPoint = new IPEndPoint(IPAddress.Parse(ToIP), ToPort);UdpNet.Instance.SendMsg("gogogo", iPEndPoint);}// Update is called once per framevoid Update(){timer += Time.deltaTime;if (timer >= maxTime && send){// send = false;timer = 0;byte[] data = TextureToTexture2D(rawImage.texture).EncodeToJPG();UdpNet.Instance.SendBytes(data, iPEndPoint);// Resources.UnloadUnusedAssets();}}public void Play(){webCam.Play();send = true;}public void Pause(){send = false;webCam.Pause();}/// 运行模式下Texture转换成Texture2Dprivate Texture2D TextureToTexture2D(Texture texture){Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);RenderTexture currentRT = RenderTexture.active;RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);Graphics.Blit(texture, renderTexture);RenderTexture.active = renderTexture;texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);texture2D.Apply();RenderTexture.active = currentRT;RenderTexture.ReleaseTemporary(renderTexture);return texture2D;}}

建两个工程,一个发送一个接收,UdpNet和ByteArray是通用的,每个工程都必须要有
1.发送工程界面
发送工程界面
2.接收界面工程
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/139669.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Android studio中如何下载sdk

打开 file -> settings 这个页面, 在要下载的 SDK 前面勾上, 然后点 apply 在 platforms 中就可以看到下载好的 SDK: Android SDK目录结构详细介绍可以参考这篇文章: 51CTO博客- Android SDK目录结构

一招解除csdn复制限制

先看这个代码 python读取英文pdf翻译成中文pdf文件导出代码 想要复制代码&#xff0c;csdn有限制怎么办&#xff08;csdn流氓&#xff0c;无耻&#xff09; 解除方法 ctrlu 看效果

什么是分布式锁?他解决了什么样的问题?

相信对于朋友们来说&#xff0c;锁这个东西已经非常熟悉了&#xff0c;在说分布式锁之前&#xff0c;我们来聊聊单体应用时候的本地锁&#xff0c;这个锁很多小伙伴都会用 ✔本地锁 我们在开发单体应用的时候&#xff0c;为了保证多个线程并发访问公共资源的时候&#xff0c;…

2023最新SSL证书在线申请系统源码 | 支持API接口

2023最新SSL证书在线申请系统源码 | 支持API接口 SSL证书保证网络安全的基本保障。向您介绍我们的在线生成SSL证书系统 支持在线生成SSL证书系统&#xff0c;用户登录可在线申请SSL&#xff0c;后台对接ssl证书API接口 测试运行环境&#xff1a;NginxPHP8.0MySQL5.7 源码下…

Android事件分发机制源码解析

触摸事件传递机制是Android中一块比较重要的知识体系&#xff0c;了解并熟悉整套的传递机制有助于更好的分析各种滑动冲突、滑动失效问题&#xff0c;更好去扩展控件的事件功能和开发自定义控件。 预备知识 MotionEvent 在Android设备中&#xff0c;触摸事件主要包括点按、长…

Android 启动优化案例:WebView非预期初始化排查

去年年底做启动优化时&#xff0c;有个比较好玩的 case 给大家分享下&#xff0c;希望大家能从我的分享里 get 到我在做一些问题排查修复时是怎么看上去又low又土又高效的。 1. 现象 在我们使用 Perfetto 进行app 启动过程性能观测时&#xff0c;在 UI 线程发现了一段 几十毫…

使用接口包装器模块简化在FPGA上实现PCIe的过程

许多最终应用程序都将基于FPGA的设计用作其解决方案的固有组件。他们通常需要PCI Express&#xff08;PCIe&#xff09;作为必不可少的功能&#xff0c;以提供与系统中其他组件的标准化接口。 从历史上看&#xff0c;PCI Express一直难以在FPGA中实现&#xff0c;因为它需要具…

【AI视野·今日Robot 机器人论文速览 第三十八期】Thu, 21 Sep 2023

AI视野今日CS.Robotics 机器人学论文速览 Thu, 21 Sep 2023 Totally 39 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Model-free tracking control of complex dynamical trajectories with machine learning Authors Zheng Meng Zhai, Mohammad…

聊聊wireshark的进阶使用功能 | 京东云技术团队

1. 前言 emmm&#xff0c;说起网络知识学习肯定离不来wireshark工具&#xff0c;这个工具能够帮助我们快速地定位网络问题以及帮助正在学习网络协议这块的知识的同学验证理论与实际的一大利器&#xff0c;平时更多的只是停留在初步的使用阶段。也是利用部门内部的网络兴趣小组…

小米笔试题——01背包问题变种

这段代码的主要思路是使用动态规划来构建一个二维数组 dp&#xff0c;其中 dp[i][j] 表示前 i 个产品是否可以组合出金额 j。通过遍历产品列表和可能的目标金额&#xff0c;不断更新 dp 数组中的值&#xff0c;最终返回 dp[N][M] 来判断是否可以组合出目标金额 M。如果 dp[N][M…

Flowable主要子流程介绍

1. 内嵌子流程 &#xff08;1&#xff09;说明 内嵌子流程又叫嵌入式子流程&#xff0c;它是一个可以包含其它活动、分支、事件&#xff0c;等的活动。我们通常意义上说的子流程通常就是指的内嵌子流程&#xff0c;它表现为将一个流程&#xff08;子流程&#xff09;定…

【word格式】mathtype公式插入 | 段落嵌入后格式对齐 | 字体大小调整 |空心字体

1. 公式嵌入 推荐在线latex编辑器&#xff0c;可以截图转 latex 识别率很高 https://www.latexlive.com/home 美中不足&#xff0c;不开会员每天只能用3次识别。 通过公式识别后&#xff0c;输出选择align环境&#xff0c;然后在mathtype中直接粘贴latex就可以转好。 2.公式…

什么是语法糖?Java中有哪些语法糖?

什么是语法糖&#xff1f;Java中有哪些语法糖&#xff1f; 语法糖 语法糖&#xff08;Syntactic Sugar&#xff09;&#xff0c;也称糖衣语法&#xff0c;是由英国计算机学家 Peter.J.Landin 发明的一个术语&#xff0c;指在计算机语言中添加的某种语法&#xff0c;这种语法对…

JavaWeb开发-08-MySQL(三)

一.多表查询 -- 多表查询: 数据准备 -- 部门管理 create table tb_dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not null unique comment 部门名称,create_time datetime not null comment 创建时间,update_time datetime not null comm…

数字赋能 融链发展 ——2023工博会数字化赋能专精特新“小巨人”企业高质量发展论坛顺利举行

编者按&#xff1a;2023年政府工作报告提出“加快传统产业和中小企业数字化转型”要求&#xff0c;按照《“十四五”促进中小企业发展规划》《关于开展中小企业数字化转型城市试点工作的通知》等文件的部署&#xff0c;通过开展城市试点&#xff0c;支持地方政府综合施策&#…

JVM 参数详解

GC有两种类型&#xff1a;Scavenge GC 和Full GC 1、Scavenge GC 一般情况下&#xff0c;当新对象生成&#xff0c;并且在Eden申请空间失败时&#xff0c;就会触发Scavenge GC&#xff0c;堆的Eden区域进行GC&#xff0c;清除非存活对象&#xff0c;并且把尚且存活的对象移动到…

绿色计算产业发展白皮书:2022年OceanBase助力蚂蚁集团减排4392tCO2e

9 月 15 日&#xff0c;绿色计算产业联盟在 2023 世界计算大会期间重磅发布了《绿色计算产业发展白皮书&#xff08;2023 版&#xff09;》。蚂蚁集团作为指导单位之一&#xff0c;联合参与了该白皮书的撰写。 白皮书中指出&#xff0c;落实“双碳”战略&#xff0c;绿色计算已…

LLM(二)| LIMA:在1k高质量数据上微调LLaMA1-65B,性能超越ChatGPT

本文将介绍在Lit-GPT上使用LoRA微调LLaMA模型&#xff0c;并介绍如何自定义数据集进行微调其他开源LLM 监督指令微调&#xff08;Supervised Instruction Finetuning&#xff09; 什么是监督指令微调&#xff1f;为什么关注它&#xff1f; 目前大部分LLM都是decoder-only&…

Leetcode 386. 字典序排数

文章目录 题目代码&#xff08;9.22 首刷看解析&#xff09; 题目 Leetcode 386. 字典序排数 代码&#xff08;9.22 首刷看解析&#xff09; 迭代DFS class Solution { public:vector<int> lexicalOrder(int n) {vector<int> ret(n);int number 1;for(int i 0…

stm32之PWM呼吸灯

呼吸灯是灯从渐亮到渐灭周而复始形成的一个效果。由于51没有PWM所以需要定时器模拟PWM才能实现呼吸灯的效果&#xff0c;但是stm32的通用定时器是有PWM模式的&#xff0c;所以不需要再用软件模拟&#xff0c;精准度也高。 本实验用的基于stm32f103C8t6。在PB8引脚上接了一个le…