基于vue3.0实现vr全景编辑器

news2024/9/25 11:20:55

随着社会的不断发现,现实生活中有很多时候会使用到全景现实,比如房地产行业vr看房,汽车行业vr看车之类的,全景可视化真实还原了现场的场景,真正做到沉浸式体验。

现在我们基于vue3.0版本开发出了一款沉浸式的编辑器,只需要使用全景相机在现场拍摄全景场景,然后将场景倒入编辑器,通过拖动图标和导航的方式绑定数据,从而实现沉浸式场景可视化。

部分洁面:

1、自定义动态添加数据绑定图标,实时监控数据运行状态

2、自定义添加文字标记,绑定文字文本,标识场景设备名称

 3、自定义添加场景标记,点击可以切换不同场景视角

4、自定义添加地图经纬度标记,查看当前标记位置

5、自定义添加音视频标记,点击查看音视频播放

 6、自定义添加网址和富文本标记,点击跳转网址查看富文本内容 

 部分代码如下:

(function (w) { // isFormat 表示是否格式化时间格式,,默认为格式化
  function $Date (isFormat = true) { // 格式化日期 前台传值方式  引用类.dateFormat(1402233166999,"yyyy-MM-dd hh:mm:ss")
    this.dateFormat = function (date, fmt = 'yyyy-MM-dd hh:mm:ss') {
      let getDate = new Date(date);
      let o = {
        'M+': getDate.getMonth() + 1,
        'd+': getDate.getDate(),
        'h+': getDate.getHours(),
        'm+': getDate.getMinutes(),
        's+': getDate.getSeconds(),
        'q+': Math.floor(
          (getDate.getMonth() + 3) / 3
        ),
        'S': getDate.getMilliseconds()
      };
      if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length));
      }
      for (let k in o) {
        if (new RegExp('(' + k + ')').test(fmt)) {
          fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
        }
      }
      return fmt;
    };
    // 当前日期时间
    this.now = isFormat ? this.dateFormat(new Date()) : new Date();

    // 当前日期
    this.date = this.dateFormat(new Date()).split(' ')[0];

    // 当前时间
    this.time = this.dateFormat(new Date()).split(' ')[1];

    // 当前月
    this.month = new Date().getMonth() + 1;

    // 当前消失
    this.hours = new Date().getHours();

    // 当前月天数
    this.monthDays = (() => {
      let nowMonth = new Date().getMonth(); // 当前月
      let nowYear = new Date().getYear(); // 当前年
      let monthStartDate = new Date(nowYear, nowMonth, 1);
      let monthEndDate = new Date(nowYear, nowMonth + 1, 1);
      let days = (monthEndDate - monthStartDate) / (1000 * 60 * 60 * 24);
      return days;
    })();

    // 本周的开始日期和结束日日期
    this.endDayOfWeek = (() => {
      let nowMonth = new Date().getMonth(); // 当前月
      let nowDay = new Date().getDate(); // 当前日
      let nowDayOfWeek = new Date().getDay(); // 今天本周的第几天
      let day = nowDayOfWeek || 7;

      const start = new Date(new Date().getFullYear(), nowMonth, nowDay - day + 1);
      const starts = new Date(new Date().getFullYear(), nowMonth, nowDay - day + 1);
      const end = new Date(new Date().getFullYear(), nowMonth, nowDay + 7 - day);
      const ends = new Date(new Date().getFullYear(), nowMonth, nowDay + 7 - day);

      starts.setHours(23);
      starts.setMinutes(59);
      starts.setSeconds(59);

      ends.setHours(23);
      ends.setMinutes(59);
      ends.setSeconds(59);

      const firstDay = isFormat ? this.dateFormat(start) : start;
      const firstDays = isFormat ? this.dateFormat(starts) : starts;
      const lastDay = isFormat ? this.dateFormat(end) : end;
      const lastDays = isFormat ? this.dateFormat(ends) : ends;
      return {firstDay, firstDays, lastDay, lastDays};
    })();

    // 当天开始时间
    this.todayBegin = (() => {
      const now = new Date();
      now.setHours(0);
      now.setMinutes(0);
      now.setSeconds(0);
      return isFormat ? this.dateFormat(now) : now;
    })();

    // 当天59时59分59秒
    this.todayEnd = (() => {
      const now = new Date();
      now.setHours(23);
      now.setMinutes(59);
      now.setSeconds(59);
      return isFormat ? this.dateFormat(now) : now;
    })();

    // 指定月的最后第一天和最后一天
    this.getNowTheMothEnd = (M) => {
      if (typeof M !== 'number') {
        throw new Error('输入数字');
      }
      if (M < 0 || M > 12) {
        console.error('日期大于1小于12');
        return false;
      }

      const now = new Date();
      let y = now.getFullYear();
      let m = M - 1;

      const firstDay = new Date(y, m, 1);
      const firstDays = new Date(y, m, 1);
      firstDays.setHours(23);
      firstDays.setMinutes(59);
      firstDays.setSeconds(59);

      const lastDay = new Date(y, m + 1, 0);
      const lastDays = new Date(y, m + 1, 0);
      lastDays.setHours(23);
      lastDays.setMinutes(59);
      lastDays.setSeconds(59);

      return {
        firstDay: isFormat ? this.dateFormat(firstDay) : firstDay,
        firstDays: isFormat ? this.dateFormat(firstDays) : firstDays,
        lastDay: isFormat ? this.dateFormat(lastDay) : lastDay,
        lastDays: isFormat ? this.dateFormat(lastDays) : lastDays
      };
    };

    // 当月的最后第一天和最后一天
    this.nowMothEnd = (() => {
      const now = new Date();
      let y = now.getFullYear();
      let m = now.getMonth();

      const firstDay = new Date(y, m, 1);
      const firstDays = new Date(y, m, 1);
      firstDays.setHours(23);
      firstDays.setMinutes(59);
      firstDays.setSeconds(59);

      const lastDay = new Date(y, m + 1, 0);
      const lastDays = new Date(y, m + 1, 0);
      lastDays.setHours(23);
      lastDays.setMinutes(59);
      lastDays.setSeconds(59);

      return {
        firstDay: isFormat ? this.dateFormat(firstDay) : firstDay,
        firstDays: isFormat ? this.dateFormat(firstDays) : firstDays,
        lastDay: isFormat ? this.dateFormat(lastDay) : lastDay,
        lastDays: isFormat ? this.dateFormat(lastDays) : lastDays
      };
    })();

    // 今年的第一天和今年的最后一天
    this.nowYearsEnd = (() => {
      const now = new Date();
      let y = now.getFullYear();
      let m = now.getMonth();
      console.log(m);

      const firstDay = new Date(y, 0, 1);
      const firstDays = new Date(y, 0, 1);
      firstDays.setHours(23);
      firstDays.setMinutes(59);
      firstDays.setSeconds(59);

      const lastDay = new Date(y, 12, 0);
      const lastDays = new Date(y, 12, 0);
      lastDays.setHours(23);
      lastDays.setMinutes(59);
      lastDays.setSeconds(59);
      return {
        firstDay: isFormat ? this.dateFormat(firstDay) : firstDay,
        firstDays: isFormat ? this.dateFormat(firstDays) : firstDays,
        lastDay: isFormat ? this.dateFormat(lastDay) : lastDay,
        lastDays: isFormat ? this.dateFormat(lastDays) : lastDays
      };
    })();

    // 指定年的第一天和今年的最后一天
    this.nowTheYearsEnd = (Y) => {
      const now = new Date();
      let y = Y;
      let m = now.getMonth();
      console.log(m);

      const firstDay = new Date(y, 0, 1);
      const firstDays = new Date(y, 0, 1);
      firstDays.setHours(23);
      firstDays.setMinutes(59);
      firstDays.setSeconds(59);

      const lastDay = new Date(y, 12, 0);
      const lastDays = new Date(y, 12, 0);
      lastDays.setHours(23);
      lastDays.setMinutes(59);
      lastDays.setSeconds(59);
      return {
        firstDay: isFormat ? this.dateFormat(firstDay) : firstDay,
        firstDays: isFormat ? this.dateFormat(firstDays) : firstDays,
        lastDay: isFormat ? this.dateFormat(lastDay) : lastDay,
        lastDays: isFormat ? this.dateFormat(lastDays) : lastDays
      };
    };

    // 当前时间最近前N天
    this.getNowBeforeNday = (N) => {
      const now = new Date().getTime();
      const before = new Date().getTime() - (24 * 60 * 60 * 1000) * N;
      return {
        now: isFormat ? this.dateFormat(new Date(now)) : new Date(now),
        before: isFormat ? this.dateFormat(new Date(before)) : new Date(before)
      };
    };

    // 当前时间后面N天
    this.getNowAfterNday = (N) => {
      const now = new Date().getTime();
      const after = new Date().getTime() + (24 * 60 * 60 * 1000) * N;
      return {
        now: isFormat ? this.dateFormat(new Date(now)) : new Date(now),
        after: isFormat ? this.dateFormat(new Date(after)) : new Date(after)
      };
    };
  }
  w.$Date = $Date;
})(window);
const date = window.$Date;
export const $Date = date;
<template>
  <div class="edit-hot_wrapper">
    <el-dialog
      v-model="dialogVisible"
      :title="`${hotSpot.id ? '修改' : '新增'}${spotTypeName(form.iconType)}标记`"
      :width="'360px'"
      :top="'10px'"
      :modal="false"
      :close-on-click-modal="false"
      :custom-class="'edit-hot_dialog'"
      :before-close="close"
    >
      <el-form :model="form" ref="ruleForm" :rules="rules">
        <el-form-item label="标记名称" required prop="name">
          <el-input v-model="form.name" placeholder="输入名称" clearable/>
        </el-form-item>
        <!--基础图标绑定-->
        <template v-if="form.iconType == 1">
          <el-form-item label="绑定数据" required>
            <el-select
              v-model="form.devices"
              placeholder="选择设备"
              filterable
              multiple
              collapse-tags
            >
              <el-option
                v-for="v in deviveData.data"
                :label="v.name"
                :value="v.id"
                :key="v.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="标记图标" required prop="spotTypes">
            <el-image
              :class="['icon-types', form.spotTypes == v.id ? 'active' : '']"
              v-for="v in hotTypes"
              :key="v.id"
              :src="v.url"
              @click="form.spotTypes = v.id"
            />
          </el-form-item>
        </template>

        <!-- 文字图标绑定-->
        <template v-if="form.iconType == 2">
          <el-form-item label="绑定数据" required prop="devices">
            <el-select
              v-model="form.devices"
              placeholder="选择设备"
              filterable
              multiple
              collapse-tags
            >
              <el-option
                v-for="v in deviveData.data"
                :label="v.name"
                :value="v.id"
                :key="v.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="文字内容" required prop="text">
            <el-input
              v-model="form.text"
              :rows="4"
              type="textarea"
              placeholder="输入文字内容"
            />
          </el-form-item>
        </template>

        <!-- 场景图标绑定-->
        <template v-if="form.iconType == 3">
          <el-form-item label="绑定场景" required prop="sceneId">
            <el-select
              v-model="form.sceneId"
              placeholder="选择场景"
            >
              <el-option
                v-for="v in scenes"
                :label="v.name"
                :value="v.id"
                :key="v.id">
              </el-option>
            </el-select>
          </el-form-item>
        </template>

        <!-- 位置图标绑定-->
        <template v-if="form.iconType == 4">
          <el-form-item label="地图位置" required prop="localtion">
            <el-input v-model="form.localtion" placeholder="输入经纬度" clearable/>
          </el-form-item>
          <el-form-item label="经纬度查询">
            <el-button type="success">查询</el-button>
          </el-form-item>
        </template>

        <!-- 位置图标绑定-->
        <template v-if="form.iconType == 5">
          <el-form-item label="媒体地址" required prop="media">
            <el-input v-model="form.media.url" placeholder="输入媒体地址" clearable/>
          </el-form-item>
          <el-form-item label="媒体类型" required>
            <el-radio-group v-model="form.media.type" class="ml-4">
              <el-radio :label="0" size="large">音频</el-radio>
              <el-radio :label="1" size="large">视频</el-radio>
            </el-radio-group>
          </el-form-item>
        </template>

        <!-- 网址图标绑定-->
        <template v-if="form.iconType == 6">
          <el-form-item label="网站地址" required prop="website">
            <el-input v-model="form.website" placeholder="输入网址" clearable/>
          </el-form-item>
        </template>

        <!-- 网址图标绑定-->
        <template v-if="form.iconType == 7">
          <el-form-item label="富文本" required prop="html">
            <el-input v-model="form.html" :rows="5" type="textarea" placeholder="输入网址" clearable/>
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="close">取消</el-button>
          <el-button type="primary" @click="save(ruleForm)">保存</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { res } from '../data/res.js';
// import store from '../../../store/index.js';
import { hotTypes } from '../utils/data.js';
import { defineEmits, defineProps } from 'vue';
import { reactive, ref, computed, onMounted } from 'vue';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
import store from '../vuex/vrViewer.js';
import { ICOM_TYPE } from '../utils/data.js';

const ruleForm = ref(null);
const rules = reactive({
  name: [
    {
      required: true,
      trigger: 'change',
      message: '标记名称必填'
    }
  ],
  devices: [
    {
      required: true,
      trigger: 'change',
      message: '绑定设备必填'
    }
  ],
  spotTypes: [
    {
      required: true,
      trigger: 'change',
      message: '标记图标类型必填'
    }
  ],
  text: [
    {
      required: true,
      trigger: 'change',
      message: '文本内容必填'
    }
  ],
  sceneId: [
    {
      required: true,
      trigger: 'change',
      message: '绑定场景必填'
    }
  ],
  localtion: [
    {
      required: true,
      trigger: 'change',
      message: '绑定位置必填'
    }
  ],
  media: [
    {
      required: true,
      trigger: 'change',
      message: '媒体地址必填'
    }
  ],
  website: [
    {
      required: true,
      trigger: 'change',
      message: '网站地址必填'
    }
  ],
  html: [
    {
      required: true,
      trigger: 'change',
      message: '富文本内容必填'
    }
  ],
});
const dialogVisible = ref(true);
const deviveData = ref(res);
const props = defineProps({
  hotSpot: {}, // 当前标记
  scenes: {}
});

let stores = useStore();
// 当前标记类型id
const iconType = computed(() => {
  return stores.state.vrViewer.type;
});

// 当前标记类型名称
const spotTypeName = () => {
  const list = Object.values(ICOM_TYPE);
  return list.find(v => v.type == form.value.iconType).name;
};

const types = ref(hotTypes);
const emits = defineEmits([
  'success',
  'close',
  'save'
]);

onMounted(() => {
  // 编辑回显示
  if (props.hotSpot.id) {
    form.value = props.hotSpot.data;
    // store.commit('vrViewer/setIconType', props.hotSpot.data.iconType);
  }
});


const form = ref({
  id: '', // 标记id
  name: '',
  devices: [],
  spotTypes: types.value[0].id, // 图标类型
  spotUrl: types.value[0].url, // 标记图表url
  iconType: stores.state.vrViewer.type,
  text: '', // 文字绑定
  sceneId: '', // 场景绑定
  localtion: '', // 位置经纬度绑定
  media: {
    type: 0, // 0代表音频, 1代表视频
    url: '' // url播放地址
  },
  website: '', // 网址
  html: '', // html绑定
});

const close = () => emits('close');

const save = async (formEl) => {
  // if (!form.value.name) {
  //   // 其他类型报错
  //   ElMessage({
  //     showClose: true,
  //     message: '输入名称',
  //     type: 'error'
  //   });
  //   return;
  // }

  // if (!form.value.devices.length) {
  //   // 其他类型报错
  //   ElMessage({
  //     showClose: true,
  //     message: '选择设备',
  //     type: 'error'
  //   });
  //   return;
  // }
  console.log(formEl, 'formEl');
  await formEl.validate((valid, fields) => {
    if (valid) {
      emits('save', form.value, props.hotSpot);
      close();
    } else {
      console.log('error submit!', fields)
    }
  })
};

const success = () => {
  emits('success');
};
</script>
<style lang="scss">
  .edit-hot_dialog {
    .el-dialog__body {
      padding: 10px 20px;
      .el-select {
        width: 245px;
      }
    }
  }
</style>
<style lang="scss" scoped>
  .icon-types {
    width: 36px;
    height: 35px;
    margin: 2px;
    border: 1px solid #ccc;
    user-select: none;
    &.active {
      border: 2px solid blue;
    }
  }
</style>

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

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

相关文章

拿捏 ---> 水仙花数+变种水仙花数

文章目录 题目描述(水仙花数)思路代码示例方法一方法二 题目描述&#xff08;变种水仙花数&#xff09;思路代码示例 题目描述(水仙花数) 求出0&#xff5e;1000之间的所有“水仙花数”并输出。“水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和确好等于该数本身&a…

ThinkPHP8知识详解:ThinkPHP8特性和功能介绍

ThinkPHP8 是一个开源的 PHP 框架&#xff0c;采用了面向对象编程和 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;提供了丰富的功能和易于使用的 API&#xff0c;是一个适用于 web 应用开发的高效框架。 ThinkPHP8具有许多强大的特性和功能&#xf…

k8s容器日志收集方案

背景 由于以下容器本身特性和现有日志采集工具的缺陷&#xff0c;开发者在收集Kubernetes分布式集群日志时常常遇到困扰&#xff1a; 容器本身特性&#xff1a; 采集目标多&#xff1a;容器本身的特性导致采集目标多&#xff0c;需要采集容器内日志、容器stdout。对于容器…

三分钟带你了解音频转文字哪个好用

在数字世界的角落里&#xff0c;有一项神奇的技术——音频转文字。它隐藏着巨大的力量和惊人的能力。它如同一位神奇的文字解码师&#xff0c;能够将听觉的旋律转化为视觉的符号&#xff0c;让语言的美妙之音在屏幕上跃然纸上。接下来&#xff0c;让我带你进入这个充满奇迹的数…

常用程序分段,编译流程

实际这些概念也要根据不同编译器有些微的区分&#xff0c;常用的结构模型应该就是LINUX程序分段以及GNU编译链的编译留成。 先看编译流程 程序分段: 堆存储和栈存储的区别 堆和栈的区别主要有五大点&#xff0c;分别是&#xff1a; 1、申请方式的不同。栈由系统自动分配&…

tinkerCAD案例:13.Ruler - Cm 标尺 - 厘米

tinkerCAD案例&#xff1a;13.Ruler - Cm 标尺 - 厘米 原文 While it’s fun to create things at any size you wish, sometimes you need to measure an exact distance. In this lesson you will learn to create an accurate ruler that measures centimeters. 虽然创建任…

六、代理模式

文章目录 一、代理模式1、代理模式的好处和缺点1.1 代理模式理解加深 一、代理模式 为什么要学习代理模式&#xff1f; 代理模式是Spring AOP 以及 Spring MVC 的底层&#xff01;&#xff01;并且还是 JAVA 的23种设计模式之一&#xff01;&#xff01; 代理模式的分类&#…

【TI毫米波雷达笔记】IWR6843AOP工程模板创建 cannot find file “libsleep_xwr68xx.aer4f“等解决方案

【TI毫米波雷达笔记】IWR6843AOP工程模板 cannot find file “libsleep_xwr68xx.aer4f” 解决方案 我在建立工程时 发现了一个问题 参考&#xff1a; blog.csdn.net/qq_16660871/article/details/126246572报错为 cannot find file "libsleep_xwr68xx.aer4f"最后检…

【Linux】深入理解缓冲区

目录 什么是缓冲区 为什么要有缓冲区 缓冲区刷新策略 缓冲区在哪里 手动设计一个用户层缓冲区 什么是缓冲区 缓冲区本质上一块内存区域&#xff0c;用来保存临时数据。缓冲区在各种计算任务中都广泛应用&#xff0c;包括输入/输出操作、网络通信、图像处理、音频处理等。 …

Nodejs 第一章(介绍)

概述 nodejs 并不是JavaScript应用&#xff0c;也不是编程语言&#xff0c;因为编程语言使用的JavaScript,Nodejs是 JavaScript的运行时。 Nodejs是构建在V8引擎之上的&#xff0c;V8引擎是由C/C编写的&#xff0c;因此我们的JavaSCript代码需要由C/C转化后再执行。 NodeJs 使…

看了这篇文章,我也会用grid布局了

grid网格布局 网格布局是由一系列水平及垂直的线构成的一种布局模式&#xff0c;使用网格&#xff0c;我们能够将设计元素进行排列&#xff0c;帮助我们设计一系列具有固定位置以及宽度的元素的页面&#xff0c;使我们的网站页面更加统一。 它将网页划分成一个个网格&#xff…

Cilium系列-6-从地址伪装从IPtables切换为eBPF

系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, 可以进一步提升 Cilium 的网络性能. 具体调优项包括不限于: 启用本地路由(Native Routing)完全替换 KubeProx…

探索大型语言模型的开源人工智能基础设施:北京开源AI Meetup回顾

原文参见Explore open source AI Infra for Large Language Models: Highlights from the Open Source AI Meetup Beijing | Cloud Native Computing Foundation 背景介绍&#xff1a; 最近&#xff0c;在 ChatGPT 的成功推动下&#xff0c;大型语言模型及其应用程序的流行度激…

递归实现 组合问题+排列问题(DFS)

递归不是循环&#xff0c;递归利用了系统栈&#xff0c;只要是函数都会被系统管理。当执行到函数地址入口时就会为函数在系统栈上分配一块内存。当函数在自己内部再次调用自己&#xff0c;那么系统又会给此时调用的函数再次分配内存&#xff0c;结果说就是层层调用。递归就是这…

【硬件设计】数字电路基础--概念、分类与基本运算

【硬件设计】数字电路基础--概念、分类与基本运算 一、数字电路基本概念二、数字电路分类&#xff08;了解&#xff09;三、数制四、数字电路中的二级管与三级管4.1 二级管4.2 三级管 五、逻辑运算5.1 逻辑与5.2 逻辑或5.3 非5.4 符合逻辑电路5.5 基本公式5.6 基本规则5.7 逻辑…

通过sql文件快速生成数据库设计文档

1.如果是springboot的java项目直接引入包即可&#xff0c;其他情况可以创建一个java项目然后引入包。 <dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependenc…

什么是小红书内容种草,品牌内容营销分析

依托于现在各种社交类平台的崛起&#xff0c;如红薯、d音、头条等&#xff0c;越来越多精彩的内容浮现出来。那么在现今时代下&#xff0c;什么是小红书内容种草&#xff0c;品牌内容营销分析&#xff01; 一、什么是小红书内容种草 1、内容种草的核心是内容 所谓的种草&#x…

SpringBoot第8讲:SpringBoot添加Logback日志

SpringBoot第8讲&#xff1a;SpringBoot添加Logback日志 本文是SpringBoot第8讲&#xff0c;对SpringBoot添加Logback日志。SpringBoot开发中如何选用日志框架呢&#xff1f; 出于性能等原因&#xff0c;Logback 目前是springboot应用日志的标配&#xff1b; 当然有时候在生产环…

身份证真伪一键验证API接口 - 通过OCR技术快速识别和验证身份证信息

身份证是我们日常生活中必不可少的证件&#xff0c;但是在实际使用中&#xff0c;我们也会遇到很多问题&#xff0c;例如身份证是否真实有效&#xff0c;身份证信息是否准确等等。这时候我们就需要用到一种能够快速识别和验证身份证信息的技术——OCR&#xff08;Optical Chara…

python怎么实现tcp和udp连接

目录 什么是tcp连接 什么是udp连接 python怎么实现tcp和udp连接 什么是tcp连接 TCP&#xff08;Transmission Control Protocol&#xff09;连接是一种网络连接&#xff0c;它提供了可靠的、面向连接的数据传输服务。 在TCP连接中&#xff0c;通信的两端&#xff08;客户端和…