【网络】网络聊天室udp

网络聊天室udp

  • 一、低耦合度代码
    • 1、代码
    • 2、测试结果
  • 二、高耦合度代码
    • 1、服务端小改
      • (1)维护一个unordered_map用户列表
      • (2)服务端代码
      • (3)客户端不改的情况下结果展示
    • 2、大改客户端(udp全双工用多线程)
        • i、结果
        • ii、代码分析
        • iii、源代码
    • 3、ls /dev/pts/
    • 4、重定向输出dup2后在终端打印效果
    • 5、利用终端创建一个简易的聊天室
      • (1)代码
      • (2)结果展示
      • (3)也可以在终端用一个命令
    • 6、代码汇总


一、低耦合度代码

1、代码

在这里插入图片描述

2、测试结果

在这里插入图片描述

二、高耦合度代码

1、服务端小改

(1)维护一个unordered_map用户列表

在这里插入图片描述

(2)服务端代码

#pragma once #include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include "Log.hpp"using func_t = std::function<std::string(const std::string&, const std::string&, uint16_t)>; // 将返回值为string,参数为const string&的函数包装起来extern Log log;uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";enum 
{SOCKET_ERR=1,BIND_ERR
};class UdpServer
{
public:// 构造函数UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip): _socketfd(0), _port(port), _ip(ip), _isrunning(false){}void Init(){// 1.创建udp套接字socket_socketfd = socket(AF_INET, SOCK_DGRAM, 0);// 创建失败if (_socketfd < 0){log(Fatal, "socket create error,socketfd:%d", _socketfd);exit(SOCKET_ERR);}// 创建成功log(Info, "socket create sucess,socketfd:%d", _socketfd);// 2.绑定端口号bind socketstruct sockaddr_in local; // 网络套接字结构体bzero(&local, sizeof(local)); // 将该套接字结构体对象全部清零local.sin_family = AF_INET; // 类型:ipv4local.sin_port = htons(_port); // 端口号:是在网络中来回发送的,我发过去要让对面知道我发的端口号是什么,所以必须是网络字节序列local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 1.string->unit_32 2.来回通信对方要知道发送的ip,所以ip的unit_32必须是网络序列的int n = bind(_socketfd, (const struct sockaddr *)&local, sizeof(local));if (n < 0){log(Fatal, "bind error, erron:%d, errno string:%s", errno, strerror(errno));exit(BIND_ERR);}log(Info, "bind sucess");}void CheckUser(const struct sockaddr_in &client, const std::string& clientip, uint16_t clientport){auto it = _online_user.find(clientip);if (it == _online_user.end()){// 添加_online_user.insert({clientip, client});std::cout << "{ " << clientip << " }" << "[ " << clientport << "]" << "#addr onlineuser sucess" << std::endl;}}void Broadcast(const std::string& info, const std::string& clientip, uint16_t clientport){for (const auto& user : _online_user){std::string message = "{ ";message += clientip;message += " }";message += "[ ";message += std::to_string(clientport);message += " ]#";message += info;socklen_t len = sizeof(user.second);sendto(_socketfd, message.c_str(), message.size(), 0, (struct sockaddr*)&(user.second), len);}}void Run(/*func_t func*/) // 对代码进行分层{_isrunning = true;char inbuffer[1024];while (_isrunning){struct sockaddr_in client;socklen_t len = sizeof(client);ssize_t n = recvfrom(_socketfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if (n < 0){log(Warning, "recvfrom error");continue;}uint16_t clientport = ntohs(client.sin_port); // 网络序列转主机序列,拿到portstd::string clientip = inet_ntoa(client.sin_addr); // 将网络序列的ip地址转化成为主机的序列的ip地址,风格是字符串类型的// 判断是不是新用户,新用户则添加到onlineuserCheckUser(client, clientip, clientport);std::string info = inbuffer;// 转发给所有人Broadcast(info, clientip, clientport);}}// 析构函数~UdpServer(){if (_socketfd > 0) {close(_socketfd);}}
private:int _socketfd; // 网络文件描述符,表示socket返回的文件描述符uint16_t _port; // 表明服务器进程的端口号std::string _ip; // ip地址,任意地址绑定为0bool _isrunning; // 判断是否运行std::unordered_map<std::string, struct sockaddr_in> _online_user; // client列表 主机序列的ip地址,网络序列的套接字信息
};

(3)客户端不改的情况下结果展示

在这里插入图片描述
出现一个比较奇葩的问题,我上面linux客户端是先链接的,发出一个消息halo,发现能够显示出来,我下面的vs是后面链接的,发了个haha,发现是能够显示的,但是我上面linux客户端发现halo被haha覆盖住了,而我们知道udp是个全双工的,就是接收消息和发送消息是可以分开的,可以套在多线程中的,但是上面消息却会被覆盖,因为在客户端的getline那边会阻塞住,会让优先级发送消息,我客户端要一直按回车才能收到别人发的消息,而不能实现消息的自动弹出,客户端只能一条一条收到消息,所以我们在客户端需要使用多线程版本的。我想实现一个我不发消息也能看到别人群聊发的消息。

2、大改客户端(udp全双工用多线程)

我们因为上面客户端不改变的情况下发现的是我要一直摁回车才能收到别人发的消息,其本质原因就是因为getline会阻塞住消息,即一条消息一发一条消息一收,所以我们下面客户端改成全双工,即接消息和发消息分开,这样能够实现我不发消息依旧能够收到别人发的消息,不需要按回车,我们看一下现象,再分析代码:

i、结果

在这里插入图片描述

ii、代码分析

在这里插入图片描述

iii、源代码
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>void Usage(std::string proc)
{std::cout << "\n\rUsages: " << proc << "serverip serverport\n" << std::endl;
}struct ThreadData
{struct sockaddr_in server;int socketfd;
};void* recv_message(void* args)
{ThreadData* td = static_cast<ThreadData*>(args);char buffer[1024];while (true){// 收数据 -- 从socket文件中的数据拿出来到buffer中,并将收到的对方的个人信息进行保存到temp中struct sockaddr_in temp;socklen_t len2 = sizeof(temp);ssize_t n = recvfrom(td->socketfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len2);if (n > 0){buffer[n] = 0;// 打印数据std::cout << buffer << std::endl;}}
}void* send_message(void* args)
{ThreadData* td = static_cast<ThreadData*>(args);std::string message;socklen_t len = sizeof(td->server);while (true){// 数据std::cout << "Please Enter# ";getline(std::cin, message);// 发送数据 -- 把数据发送到socketfd文件中,并将server信息提炼出来发送给server,可以理解成唤醒serversendto(td->socketfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len);}
}// ./udpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}std::string serverip = argv[1]; // serveripuint16_t serverport = std::stoi(argv[2]); // serverportstruct ThreadData td;// 给谁发bzero(&td.server, sizeof(td.server));td.server.sin_family = AF_INET;td.server.sin_port = htons(serverport);td.server.sin_addr.s_addr = inet_addr(serverip.c_str());td.socketfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建套接字if (td.socketfd < 0){std::cout << "socket create error" << std::endl;return 1;}pthread_t recver;pthread_t sender;pthread_create(&recver, nullptr, recv_message, &td);pthread_create(&sender, nullptr, send_message, &td);pthread_join(recver, nullptr);pthread_join(sender, nullptr);close(td.socketfd);return 0;
}

3、ls /dev/pts/

我们发现的是/dev/pts/的3号文件是我们的1号终端,我们发送消息给3号文件就是发送给了1号终端了。
在这里插入图片描述

4、重定向输出dup2后在终端打印效果

test.cc:
在这里插入图片描述

g++ test.cc

在这里插入图片描述

5、利用终端创建一个简易的聊天室

(1)代码

在这里插入图片描述

(2)结果展示

在这里插入图片描述

(3)也可以在终端用一个命令

这里的3是你需要ls 命令去看哪个终端能用的文件信息的,因为linux下一切皆文件,那么终端也是文件。
在这里插入图片描述

6、代码汇总

udpserver.hpp:

#pragma once #include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include "Log.hpp"using func_t = std::function<std::string(const std::string&, const std::string&, uint16_t)>; // 将返回值为string,参数为const string&的函数包装起来extern Log log;uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";enum 
{SOCKET_ERR=1,BIND_ERR
};class UdpServer
{
public:// 构造函数UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip): _socketfd(0), _port(port), _ip(ip), _isrunning(false){}void Init(){// 1.创建udp套接字socket_socketfd = socket(AF_INET, SOCK_DGRAM, 0);// 创建失败if (_socketfd < 0){log(Fatal, "socket create error,socketfd:%d", _socketfd);exit(SOCKET_ERR);}// 创建成功log(Info, "socket create sucess,socketfd:%d", _socketfd);// 2.绑定端口号bind socketstruct sockaddr_in local; // 网络套接字结构体bzero(&local, sizeof(local)); // 将该套接字结构体对象全部清零local.sin_family = AF_INET; // 类型:ipv4local.sin_port = htons(_port); // 端口号:是在网络中来回发送的,我发过去要让对面知道我发的端口号是什么,所以必须是网络字节序列local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 1.string->unit_32 2.来回通信对方要知道发送的ip,所以ip的unit_32必须是网络序列的int n = bind(_socketfd, (const struct sockaddr *)&local, sizeof(local));if (n < 0){log(Fatal, "bind error, erron:%d, errno string:%s", errno, strerror(errno));exit(BIND_ERR);}log(Info, "bind sucess");}void CheckUser(const struct sockaddr_in &client, const std::string& clientip, uint16_t clientport){auto it = _online_user.find(clientip);if (it == _online_user.end()){// 添加_online_user.insert({clientip, client});std::cout << "{ " << clientip << " }" << "[ " << clientport << "]" << "#addr onlineuser sucess" << std::endl;}}void Broadcast(const std::string& info, const std::string& clientip, uint16_t clientport){for (const auto& user : _online_user){std::string message = "{ ";message += clientip;message += " }";message += "[ ";message += std::to_string(clientport);message += " ]#";message += info;socklen_t len = sizeof(user.second);sendto(_socketfd, message.c_str(), message.size(), 0, (struct sockaddr*)&(user.second), len);}}void Run(/*func_t func*/) // 对代码进行分层{_isrunning = true;char inbuffer[1024];while (_isrunning){struct sockaddr_in client;socklen_t len = sizeof(client);ssize_t n = recvfrom(_socketfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if (n < 0){log(Warning, "recvfrom error");continue;}uint16_t clientport = ntohs(client.sin_port); // 网络序列转主机序列,拿到portstd::string clientip = inet_ntoa(client.sin_addr); // 将网络序列的ip地址转化成为主机的序列的ip地址,风格是字符串类型的// 判断是不是新用户,新用户则添加到onlineuserCheckUser(client, clientip, clientport);std::string info = inbuffer;// 转发给所有人Broadcast(info, clientip, clientport);}}// 析构函数~UdpServer(){if (_socketfd > 0) {close(_socketfd);}}
private:int _socketfd; // 网络文件描述符,表示socket返回的文件描述符uint16_t _port; // 表明服务器进程的端口号std::string _ip; // ip地址,任意地址绑定为0bool _isrunning; // 判断是否运行std::unordered_map<std::string, struct sockaddr_in> _online_user; // client列表 主机序列的ip地址,网络序列的套接字信息
};

udpclient.cc:

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "terminal.hpp"void Usage(std::string proc)
{std::cout << "\n\rUsages: " << proc << "serverip serverport\n" << std::endl;
}struct ThreadData
{struct sockaddr_in server;int socketfd;std::string serverip;
};void* recv_message(void* args)
{openterminal();ThreadData* td = static_cast<ThreadData*>(args);char buffer[1024];while (true){// 清空memset(buffer, 0, sizeof(buffer));// 收数据 -- 从socket文件中的数据拿出来到buffer中,并将收到的对方的个人信息进行保存到temp中struct sockaddr_in temp;socklen_t len2 = sizeof(temp);ssize_t n = recvfrom(td->socketfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len2);if (n > 0){buffer[n] = 0;// 打印数据std::cerr << buffer << std::endl;}}
}void* send_message(void* args)
{ThreadData* td = static_cast<ThreadData*>(args);std::string message;socklen_t len = sizeof(td->server);std::string welcome = td->serverip;welcome += "coming...";sendto(td->socketfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len);while (true){// 数据std::cout << "Please Enter# ";getline(std::cin, message);// 发送数据 -- 把数据发送到socketfd文件中,并将server信息提炼出来发送给server,可以理解成唤醒serversendto(td->socketfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len);}
}// ./udpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}std::string serverip = argv[1]; // serveripuint16_t serverport = std::stoi(argv[2]); // serverportstruct ThreadData td;// 给谁发bzero(&td.server, sizeof(td.server));td.server.sin_family = AF_INET;td.server.sin_port = htons(serverport);td.server.sin_addr.s_addr = inet_addr(serverip.c_str());td.socketfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建套接字if (td.socketfd < 0){std::cout << "socket create error" << std::endl;return 1;}td.serverip = serverip;pthread_t recver;pthread_t sender;pthread_create(&recver, nullptr, recv_message, &td);pthread_create(&sender, nullptr, send_message, &td);pthread_join(recver, nullptr);pthread_join(sender, nullptr);close(td.socketfd);return 0;
}

main.cc:

#include "udp.hpp"
#include "Log.hpp"
#include <memory>
#include <cstdio>
#include <vector>Log log;void Usage(std::string proc)
{std::cout << "\n\rUsages: " << proc << "port[1024+]\n" << std::endl;
}std::string Handler(const std::string& info, const std::string& ip, uint16_t port)
{std::cout << "{ " << ip << " }" << "[ " << port << "]" << "# " << info << std::endl;std::string res = "recv a message# ";res += info;std::cout << res << std::endl;return res;
}bool SafeCheck(const std::string& cmd)
{std::vector<std::string> word_key = {"rm","top","cp","yum","while","kill","unlink""uninstall","top"};for (auto &word : word_key){auto pos = cmd.find(word);if (pos != std::string::npos){return false;}}return true;
}std::string ExcuteCommand(const std::string& cmd)
{std::cout << "get a massage:" << cmd << std::endl;// 做一个保护if (!SafeCheck(cmd)) return "bad man";FILE* fp = popen(cmd.c_str(), "r"); // 管道创建好,子进程创建好,子进程通过管道放到父进程if (nullptr == fp){perror("popen failed");return "error";}std::string result;char buffer[4096];while (true){char* ok = fgets(buffer, sizeof(buffer), fp); // 写到buffer缓冲区中if (ok == nullptr){break;}result += buffer;}pclose(fp);return result;
}// 以后用的是./udpserver + port
int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(0);}uint16_t port = std::stoi(argv[1]);std::unique_ptr<UdpServer> svr(new UdpServer(port)); // new一个对象svr->Init(); // 初始化svr->Run(/*Handler*/);  // 跑起来
}

terminal.hpp:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>std::string terminal = "/dev/pts/3";int openterminal()
{int fd = open(terminal.c_str(), O_WRONLY);if (fd < 0){std::cerr << "open terminal err" << std::endl;return 1;}dup2(fd, 2); // 重定向到标准错误return 0;
}

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

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

相关文章

stats 监控 macOS 系统

Stats 监控 macOS 系统 CPU 利用率GPU 利用率内存使用情况磁盘利用率网络使用情况电池电量 brew install stats参考 stats github

pythonGame-实现简单的贪食蛇游戏

通过python简单复现贪食蛇游戏。 使用到的库函数&#xff1a; import pygame import time import random 游戏源码&#xff1a; import pygame import time import randompygame.init()white (255, 255, 255) yellow (255, 255, 102) black (0, 0, 0) red (213, 50, 80…

封装和桥接Unity 协程体系

简介 协程&#xff08;Coroutine&#xff09;在C#中是一种特殊的函数&#xff0c;它允许开发者编写可以暂停执行并在未来某个时刻恢复执行的代码块。协程通常用于实现异步操作&#xff0c;如延时执行、等待某个事件发生、或者分段执行复杂的任务。在Unity游戏引擎中&#xff0c…

go-kratos 学习笔记(7) 服务发现服务间通信grpc调用

服务发现 Registry 接口分为两个&#xff0c;Registrar 为实例注册和反注册&#xff0c;Discovery 为服务实例列表获取 创建一个 Discoverer 服务间的通信使用的grpc&#xff0c;放到data层&#xff0c;实现的是从uses服务调用orders服务 app/users/internal/data.go 加入 New…

上传文件传参 pc端vue的formData

formData let formData new FormData(); formData.append("file", blob, ref ".png"); //添加参数并且重新命名文件名称 if(ref.toString().indexOf(qrcode) > 0) formData.append(noStbg, true)//添加参数 uploadType(formData, sour…

《人工智能大语言模型技术发展研究报告(2024)》【下载】

《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》下载 自2023年起&#xff0c;大模型技术产品的快速迭代和升级&#xff0c;已经成为全球科技竞争的关键因素。由中国软件评测中心发布的《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》…

LLM - 理解 Transformer 的位置编码 sin cos 的作用与原理

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140697827 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 Transformer 模型中的位置编码是关键技术,通过为每个词嵌入向量添加位…

哈希表相关的力扣题和讲解和Java、C++常用的数据结构(哈希法)

20240725 一、什么时候适用什么样的结构。1.java中1.1 HashSet&#xff1a;1.2 TreeSet&#xff1a;1.3 LinkedHashSet&#xff1a;1.4 HashMap&#xff1a;1.5 TreeMap&#xff1a;1.6 LinkedHashMap&#xff1a;1.7 总结 2. c中2.1 std::unordered_set&#xff1a;2.2 std::s…

亚信安慧AntDB亮相PostgreSQL中国技术大会,获“数据库最佳应用奖”并分享数据库应用实践

7月12日&#xff0c;第13届PostgreSQL中国技术大会在杭州顺利举办&#xff0c;亚信安慧AntDB数据库荣获“数据库最佳应用奖”。大会上&#xff0c;亚信安慧AntDB数据库同事带来《基于AntDB的CRM系统全域数据库替换实践》和《亚信安慧AntDB数据库运维之路》两场精彩演讲&#xf…

vue3前端架构---打包配置

最近看到几篇vue3配置项的文章&#xff0c;转载记录一下 Vue3.2 vue/cli-service 打包 chunk-vendors.js 文件过大导致页面加载缓慢解决方案-CSDN博客文章浏览阅读2k次&#xff0c;点赞8次&#xff0c;收藏9次。Vue3.2 vue/cli-service 打包 chunk-vendors.js 文件过大导致页…

【企业级开发模型】Git分支设计模型 | 企业级项目挂历实战_准备工作开发场景实操

目录 3.Git分支设计模型 3.1master分支 3.2release分支 3.3develop分支 3.4feature分支 3.5hotfix分支 4.企业级项目挂历实战_准备工作&开发场景实操学习文档 3.Git分支设计模型 对于我们开发人员来说&#xff0c;对于不同的场景/环境&#xff0c;来设计分支模型。…

Vue3 + Vite 打包引入图片错误

1. 具体报错 报错信息 报错代码 2. 解决方法 改为import引入&#xff0c;注意src最好引用为符引入&#xff0c;不然docker部署的时候可能也会显示不了 <template><img :src"loginBg" alt""> </template><script langts setup> …

企元数智引领新零售合规分销系统免费送

企元数智近日宣布推出全新的新零售合规分销系统&#xff0c;并免费向企业提供这一创新解决方案。这一举措旨在帮助更多企业实现数字化转型&#xff0c;提高管理效率&#xff0c;促进业务增长。 新零售合规分销系统是企元数智引领的一项全新数字解决方案&#xff0c;涵盖了销售数…

华为强制恢复出厂设置后如何恢复数据?数据重生的2个方法介绍

华为作为全球知名的手机品牌&#xff0c;其产品在市场上广受欢迎。然而&#xff0c;有时由于各种原因&#xff0c;我们可能需要强制恢复出厂设置&#xff0c;这往往意味着数据的丢失。那么&#xff0c;如何在华为强制恢复出厂设置后&#xff0c;让数据“重生”呢&#xff1f;本…

通信类IEEE会议——第四届通信技术与信息科技国际学术会议(ICCTIT 2024)

[IEEE 独立出版&#xff0c;中山大学主办&#xff0c;往届均已见刊检索] 第四届通信技术与信息科技国际学术会议&#xff08;ICCTIT 2024&#xff09; 2024 4th International Conference on Communication Technology and Information Technology 重要信息 大会官网&#xf…

ETL数据集成丨将PostgreSQL数据库数据实时同步至PostgreSQL

前言 我们在进行数据集成、实时数据同步中&#xff0c;经常会出现在同一个数据库中做数据同步和复制、实时分析和报告、负载均衡和高可用性等场景&#xff0c;这次我们以PostgreSQL为例&#xff0c;通过ETLCloud工具&#xff0c;进行同数据库中数据实时同步的步骤应该如何设置…

无人机组装与操作实训课程详解

一、课程名称与目标 课程名称&#xff1a;无人机组装与操作实训课程 课程目标&#xff1a;本课程旨在培养学员对无人机组装技术的深入理解和实际操作能力&#xff0c;使学员能够独立完成无人机的组装、调试和日常维护工作&#xff0c;并具备一定的无人机操作能力和安全意识。…

ZStack Cloud 5.1.8正式发布——GPU运维、物理机硬件监控、克隆云主机网络配置三大亮点简析

云轴科技ZStack Cloud云平台是遵循“简单、弹性、健壮、智能”的“4S”特性的私有云和无缝混合云产品。ZStack Cloud 5.1.8版本正式发布&#xff0c;从用户业务场景和实际需求出发&#xff0c;丰富和完善平台功能&#xff0c;推出一系列重要功能和多项改进&#xff0c;覆盖云主…

ElasticSearch(五)— 文本分析与分词

一、文本分析 文本分析( analysis )是在文档被发送并加入倒排索引之前&#xff0c;Elasticsearch 在其主体上进行的操作。在文档被加入索引之前&#xff0c;Elasticsearch 让每个被分析字段经过一系列的处理步骤。 字符过滤–使用字符过滤器转变字符。文本切分为分词—将文本…

视频怎么加密?常见的四种视频加密方法和软件

视频加密是一种重要的技术手段&#xff0c;用于保护视频内容不被未经授权的用户获取、复制、修改或传播。在加密过程中&#xff0c;安企神软件作为一种专业的加密工具&#xff0c;可以发挥重要作用。 以下将详细介绍如何使用安企神软件对视频进行加密&#xff0c;并探讨视频加密…