Untiy UDP局域网 异步发送图片

news2024/11/25 10:56:58

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

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

    #endregion


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

    //读取Int16
    public Int16 ReadInt16()
    {
        if (length < 2) return 0;
        Int16 ret = BitConverter.ToInt16(bytes, readIdx);
        readIdx += 2;
        CheckAndMoveBytes();
        return ret;
    }

    //读取Int32
    public 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 update
    void 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 frame
    void 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 update
    void 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 frame
    void 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转换成Texture2D
    private 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.coloradmin.cn/o/1033660.html

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

相关文章

搭建ELK+Filebead+zookeeper+kafka实验(详细版)

一、ELKFilebeadzookeeperkafka架构 第一层&#xff1a;数据采集层&#xff08;Filebeat&#xff09; 数据采集层位于最左边的业务服务集群上&#xff0c;在每个业务服务器上面安装了filebead做日志收集&#xff0c;然后把采集到的原始日志发送到kafkazookeeper集群上。 第二…

【常用代码15】文字单词超出强制分割换行,word-break: break-all;和word-wrap: break-word;的区别

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 文件上传后显示文件名&#xff0c;名称过长&#xff0c;超出div 有些文件名如下图 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 一般图片上传&#xff0c;要展示文件名&#x…

精品Python数字藏品购物商城爬虫-可视化大屏

《[含文档PPT源码等]精品基于Python实现的数字藏品爬虫》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技术&#xff1a;JavaScript、VUE.js&a…

pytest简明教程

1. 简介 pytest是一款基于Python的测试框架。与Python自带的unittest相比&#xff0c;pytes语法更加简洁&#xff0c;断言更加强大&#xff0c;并且在自动测试以及插件生态上比unittest都要更加强大。 1.1. 安装pytest pip install pytest1.2. pytest命名规则 pytest默认会…

基于Java+SpringBoot+Vue物流管理小程序系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

selenium-webdriver 阿里云ARMS 自动化巡检

很久没更新了&#xff0c;今天分享一篇关于做项目巡检的内容&#xff0c;这部分&#xff0c;前两天刚在公司做了部门分享&#xff0c;趁着劲还没过&#xff0c;发出来跟大家分享下。 一、本地巡检实现 1. Selenium Webdriver(SW) 简介 Selenium Webdriver&#xff08;以下简称…

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

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

一、博弈论概述

知人者智&#xff0c;自知者明&#xff1b;胜人者力&#xff0c;自胜者强&#xff1b;小胜者术&#xff0c;大胜者德。 一、什么是“博弈” &#xff08;一&#xff09;博弈的定义 博&#xff1a;博览全局&#xff1b;弈&#xff1a;对弈棋局&#xff0c;最后做到谋定而动。…

文件包含漏洞的 00截断

isset&#xff08;&#xff09;函数若变量不存在则返回 FALSE&#xff1b;若变量存在且其值为NULL&#xff0c;也返回 FALSE。若变量存在且值不为NULL&#xff0c;则返回 TURE %00是被服务器解码为0x00发挥了截断作用。核心是chr(0)字符 00截断上传原理 - 知乎 协议参考地址&…

科研之路(2023.9.21)

惰轮 麦轮 https://mp.weixin.qq.com/s/sjb3O91auADKN7iDsut0jA 理解底盘代码

FL Studio 21内置鼓机FPC怎么用 常用编曲鼓点怎么排列

FL Studio 21内置鼓机FPC怎么用&#xff1f;FPC是一款模拟硬件打击垫建模的鼓机&#xff0c;使用方法和硬件打击垫很像&#xff0c;但是多出了修改采样等更加细节的功能。常用鼓点怎么排列&#xff1f;电子音乐中常见的鼓点有4/4拍鼓组和Trap类型鼓组。 FL Studio Win-安装包&a…

【ODPS 新品发布第 2 期】实时数仓 Hologres:推出计算组实例/支持 JSON 数据/向量计算+大模型等新能力

云布道师 阿里云 ODPS 系列产品以 MaxCompute、DataWorks、Hologres 为核心&#xff0c;致力于解决用户多元化数据的计算需求问题&#xff0c;实现存储、调度、元数据管理上的一体化架构融合&#xff0c;支撑交通、金融、科研、等多场景数据的高效处理&#xff0c;是目前国内最…

S7通信协议的挑高点

目录 1. S7协议之布尔操作 2. S7协议之PDU读取 3 S7协议之多组读取 在电气学习的路上&#xff0c;西门子PLC应该是每个人的启蒙PLC&#xff0c;从早期的S7-300/400PLC搭建Profibus-DP网络开始接触&#xff0c;到后来的S7-200Smart PLC&#xff0c;再到现在的S7-1200/1500 PLC…

leetcode 10. 正则表达式匹配

2023.9.20 感觉是目前做过dp题里最难的一题了... 本题首要的就是需要理解题意&#xff0c;翻了评论区我才发现之前一直理解的题意是错的。 我原来理解的 “ *匹配0次” 是指&#xff1a;*直接消失&#xff0c;不会影响到前面的字符。 但是*和前一个字符其实是连体的&#xff0…

学习路之PHP--lumen安装配置

一、下载lumen源码 composer create-project --prefer-dist laravel/lumen blog 安装lumen-generator composer require flipbox/lumen-generator 二、配置 bootstrap\app.php 97行 $app->register(Flipbox\LumenGenerator\LumenGeneratorServiceProvider::class);三、生成…

MQ - 24 RabbitMQ集群架构设计与实现

文章目录 导图集群构建节点发现元数据存储数据可靠性镜像队列仲裁队列安全控制传输加密身份认证资源鉴权可观测性总结导图 集群构建 集群构建由节点发现和元数据存储两部分组成。RabbitMQ 也是一样的实现思路。 节点发现 在节点发现方面,RabbitMQ 通过插件化的方式支持了多…

Centos下载配置Maven

Linux下安装配置Maven 注意&#xff1a;没配置JDK的先把JDK给配置了&#xff0c;JDK环境变量名为JAVA_HOME 1、安装wget命令 如果需要通过使用wget命令&#xff0c;直接通过网络下载maven安装包时&#xff0c;需要在linux系统中安装wget命令。 yum -y install wget2、下载m…

基于SpringBoot的企业客户管理系统的设计与实现【附PPT|万字文档(LW)和搭建文档】

主要功能 后台登录&#xff1a; 可注册员工&#xff1a;工号、密码、姓名、身份证、手机、邮箱 员工&#xff1a; ①首页、个人中心、修改密码、个人信息 ②客户信息管理、项目信息管理、项目收益管理等 后台登录&#xff1a; 管理员&#xff1a; ①首页、个人中心、修改密码、…

【Flowable】Flowable自动生成的数据库表的含义

一、Flowable简介 Flowable是一个开源的工作流引擎&#xff0c;它的主要目标是提供一个灵活、可扩展、可靠的流程管理系统。Flowable通过提供一组API和工具&#xff0c;使组织能够自动化和管理其业务流程。 二、Flowable中的数据库 Flowable使用数据库来存储和管理其运行时的…

qt matlab 混合编程

1.环境的说明 matlab 2021a qt 5.12.10 qt creator 4.13.1 opencv 4.3.0 eigen-3.4.0/eigen-3.4.0 2.matlab 中导出dill 以aberr_analy1的导出dill举例 命令行中输入&#xff1a;deploytool 2. 选择LIbrarycompiler 3type 选择c 4,选择相应的 5. 点击package 选择保存的路径…