【探索Linux】—— 强大的命令行工具 P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
阅读导航
- 引言
- 一、UDP协议
- 二、UDP网络程序模拟实现
- 1. 预备代码
- ⭕makefile文件
- ⭕打印日志文件
- ⭕打开指定的终端设备文件,并将其作为标准错误输出的目标文件描述符
- 2. UDP 服务器端实现(UdpServer.hpp)
- 3. UDP 客户端实现(main函数)
- 温馨提示
引言
在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。本文将延续上文内容,重点讨论简单的UDP网络程序模拟实现。通过本文的学习,读者将能够深入了解UDP协议的实际应用,并掌握如何编写简单的UDP网络程序。让我们一起深入探讨UDP网络程序的实现细节,为网络编程的学习之旅添上一份精彩的实践经验。
一、UDP协议
UDP(User Datagram Protocol)是一种无连接的、轻量级的网络传输协议,它提供了快速、简单的数据传输服务。下面是一个简单的UDP程序实现示例,包括一个UDP服务器和一个UDP客户端。详介绍可以看上一篇文章:UDP协议介绍 | TCP协议介绍 | UDP 和 TCP 的异同
二、UDP网络程序模拟实现
1. 预备代码
⭕makefile文件
.PHONY:all
all:udpserver udpclientudpserver:Main.ccg++ -o $@ $^ -std=c++11
udpclient:UdpClient.ccg++ -o $@ $^ -lpthread -std=c++11.PHONY:clean
clean:rm -f udpserver udpclient
这段代码是一个简单的 Makefile 文件,用于编译 UDP 服务器(udpserver)和 UDP 客户端(udpclient)的程序。在这个 Makefile 中定义了两个规则:
- all:表示默认的目标,依赖于 udpserver 和 udpclient 目标,即执行 make 命令时会编译 udpserver 和 udpclient。
- clean:用于清理生成的可执行文件 udpserver 和 udpclient。
在 Makefile 中使用了一些特殊的关键字和变量:
- .PHONY:声明 all 和 clean 是伪目标,不是真正的文件名。
- $@:表示目标文件名。
- $^:表示所有依赖文件列表。
- -std=c++11:指定 C++ 的编译标准为 C++11。
- -lpthread:链接 pthread 库,用于多线程支持。
⭕打印日志文件
#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen; // 默认输出方式为屏幕打印path = "./log/"; // 默认日志文件存放路径}void Enable(int method){printMethod = method; // 设置日志输出方式(屏幕、单个文件、分类文件)}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl; // 屏幕打印日志信息break;case Onefile:printOneFile(LogFile, logtxt); // 将日志信息追加写入单个文件break;case Classfile:printClassFile(level, logtxt); // 将日志信息追加写入分类文件break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname; // 构建日志文件的完整路径int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // 打开文件,如果文件不存在则创建if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size()); // 将日志信息写入文件close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // 构建分类文件名,例如"log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt); // 将日志信息追加写入分类文件}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);printLog(level, logtxt); // 打印日志信息}private:int printMethod; // 日志输出方式std::string path; // 日志文件存放路径
};
该代码实现了一个简单的日志记录类(Log),其中包括设置日志输出方式(屏幕、单个文件、分类文件)和打印日志信息的功能。
Log
类是一个用于记录日志的类。Enable
函数用于设置日志输出方式,可以选择屏幕打印、单个文件或分类文件。printLog
函数根据设置的日志输出方式,将日志信息打印到屏幕、追加写入单个文件或分类文件。printOneFile
函数用于将日志信息追加写入单个文件。printClassFile
函数用于将日志信息追加写入分类文件。levelToString
函数将日志级别转换为对应的字符串表示。operator()
函数是重载的函数调用运算符,用于打印日志信息。path
是日志文件存放路径,默认为"./log/"。printMethod
是日志输出方式,默认为屏幕打印。SIZE
定义了缓冲区大小。Info
、Debug
、Warning
、Error
、Fatal
是日志级别的定义。Screen
、Onefile
、Classfile
是日志输出方式的定义。LogFile
是单个文件名的定义。
⭕打开指定的终端设备文件,并将其作为标准错误输出的目标文件描述符
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>// 定义要打开的终端设备文件路径
std::string terminal = "/dev/pts/6";// 打开指定的终端设备文件,并将其作为标准错误输出的目标文件描述符
int OpenTerminal()
{// 使用open函数以只写方式打开终端设备文件int fd = open(terminal.c_str(), O_WRONLY);if(fd < 0){// 如果打开终端设备文件失败,则输出错误信息到标准错误输出std::cerr << "open terminal error" << std::endl;return 1; // 返回错误代码}// 将终端设备文件的文件描述符复制给标准错误输出的文件描述符// 这样标准错误输出就会重定向到指定的终端设备上dup2(fd, 2);// 如果需要在此处输出信息到标准错误输出,可以使用printf等函数// 关闭文件描述符// close(fd);return 0; // 返回成功代码
}
这段代码的作用是打开一个终端设备文件 “/dev/pts/6”,将其作为标准错误输出(stderr)的目标文件描述符,实现将错误信息输出到指定的终端设备上。
terminal
变量存储了要打开的终端设备文件路径 “/dev/pts/6”。OpenTerminal
函数尝试打开指定的终端设备文件,并将其作为标准错误输出的目标文件描述符。- 首先使用
open
函数打开终端设备文件,以只写方式(O_WRONLY)。 - 如果成功打开终端设备文件,则将其文件描述符复制给标准错误输出的文件描述符(2),即
dup2(fd, 2)
,这样标准错误输出就会重定向到该终端设备上。 - 如果打开终端设备文件失败,则输出错误信息到标准错误输出,并返回错误代码 1。
- 最后函数返回0表示成功。
- 首先使用
2. UDP 服务器端实现(UdpServer.hpp)
#pragma once#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include "Log.hpp"// 使用Log类记录日志信息
Log lg;enum {SOCKET_ERR = 1,BIND_ERR
};uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";
const int size = 1024;class UdpServer {
public:UdpServer(const uint16_t& port = defaultport, const std::string& ip = defaultip): sockfd_(0), port_(port), ip_(ip), isrunning_(false){}void Init() {// 1. 创建UDP socketsockfd_ = socket(AF_INET, SOCK_DGRAM, 0); // PF_INETif (sockfd_ < 0) {lg(Fatal, "socket create error, sockfd: %d", sockfd_);exit(SOCKET_ERR);}lg(Info, "socket create success, sockfd: %d", sockfd_);// 2. 绑定socketstruct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_); // 端口号需要转换为网络字节序local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将IP地址转换为网络字节序if (bind(sockfd_, (const struct sockaddr*)&local, sizeof(local)) < 0) {lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));}void CheckUser(const struct sockaddr_in& client, const std::string clientip, uint16_t clientport) {// 检查用户是否已经存在在线用户列表中auto iter = online_user_.find(clientip);if (iter == online_user_.end()) {online_user_.insert({clientip, client});std::cout << "[" << clientip << ":" << clientport << "] add to online user." << 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 += std::to_string(clientport);message += "]# ";message += info;socklen_t len = sizeof(user.second);sendto(sockfd_, message.c_str(), message.size(), 0, (struct sockaddr*)(&user.second), len);}}void Run() {isrunning_ = true;char inbuffer[size];while (isrunning_) {struct sockaddr_in client;socklen_t len = sizeof(client);// 接收客户端发送的消息ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if (n < 0) {lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));continue;}// 获取客户端的IP地址和端口号uint16_t clientport = ntohs(client.sin_port);std::string clientip = inet_ntoa(client.sin_addr);// 检查用户是否已经存在在线用户列表中CheckUser(client, clientip, clientport);std::string info = inbuffer;// 将接收到的消息广播给所有在线用户Broadcast(info, clientip, clientport);}}~UdpServer() {if (sockfd_ > 0)close(sockfd_);}private:int sockfd_; // 网络文件描述符std::string ip_; // 服务器IP地址uint16_t port_; // 服务器端口号bool isrunning_; // 服务器运行状态std::unordered_map<std::string, struct sockaddr_in> online_user_; // 在线用户列表
};
Log.hpp
是用于记录日志信息的头文件。lg
是一个Log
类的对象,用于输出日志信息。enum
定义了两个错误类型:SOCKET_ERR
和BIND_ERR
,分别表示 socket 创建错误和绑定错误。defaultport
和defaultip
分别设置默认的端口号和 IP 地址。size
定义接收缓冲区的大小为 1024 字节。UdpServer
类封装了一个 UDP 服务器。- 构造函数
UdpServer
接受端口号和 IP 地址作为参数,并初始化成员变量。 Init
函数用于初始化 UDP 服务器,其中:- 创建 UDP socket,并检查创建是否成功。
- 绑定 socket 到指定的 IP 地址和端口号,并检查绑定是否成功。
CheckUser
函数用于检查用户是否已经存在在线用户列表中,如果不存在则将其添加到列表中。Broadcast
函数用于向所有在线用户广播消息,其中:- 消息格式为
[发送者IP:发送者端口号]# 消息内容
。 - 使用
sendto
函数发送消息给每个在线用户。
- 消息格式为
Run
函数是 UDP 服务器的主循环,其中:- 循环接收客户端发送的消息,并将其广播给所有在线用户。
- 对每个客户端,获取其 IP 地址和端口号,并进行用户检查和消息广播。
~UdpServer
析构函数关闭网络文件描述符。sockfd_
是网络文件描述符,用于创建和管理网络连接。ip_
是服务器的 IP 地址。port_
是服务器的端口号。isrunning_
表示服务器的运行状态,用于控制循环退出。online_user_
是一个无序映射,用于保存在线用户的 IP 地址和对应的sockaddr_in
结构体。
3. UDP 客户端实现(main函数)
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "Terminal.hpp"using namespace std;// 函数声明:打印程序的使用方法
void Usage(std::string proc);// 结构体:用于传递线程参数
struct ThreadData
{struct sockaddr_in server; // 服务器地址结构体int sockfd; // socket 文件描述符std::string serverip; // 服务器 IP 地址
};// 线程函数:接收消息
void *recv_message(void *args);// 线程函数:发送消息
void *send_message(void *args);// 主函数
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]); // 打印使用方法exit(0);}// 解析命令行参数std::string serverip = argv[1]; // 服务器 IP 地址uint16_t serverport = std::stoi(argv[2]); // 服务器端口号// 初始化 ThreadData 结构体struct ThreadData td;bzero(&td.server, sizeof(td.server)); // 清零服务器地址结构体td.server.sin_family = AF_INET; // 设置地址族为 IPv4td.server.sin_port = htons(serverport); // 设置端口号(转换为网络字节序)td.server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 设置服务器 IP 地址(转换为网络字节序)// 创建 UDP sockettd.sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (td.sockfd < 0){cout << "socket error" << endl;return 1;}td.serverip = serverip; // 存储服务器 IP 地址pthread_t recvr, sender; // 定义接收消息和发送消息的线程pthread_create(&recvr, nullptr, recv_message, &td); // 创建接收消息线程pthread_create(&sender, nullptr, send_message, &td); // 创建发送消息线程// 等待接收消息和发送消息的线程退出pthread_join(recvr, nullptr);pthread_join(sender, nullptr);close(td.sockfd); // 关闭 socketreturn 0;
}// 函数实现:打印程序的使用方法
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n" << std::endl;
}// 线程函数实现:接收消息
void *recv_message(void *args)
{ThreadData *td = static_cast<ThreadData *>(args); // 强制类型转换为 ThreadData 结构体指针char buffer[1024]; // 接收消息的缓冲区while (true){memset(buffer, 0, sizeof(buffer)); // 清空缓冲区struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s = recvfrom(td->sockfd, buffer, 1023, 0, (struct sockaddr *)&temp, &len); // 接收消息if (s > 0){buffer[s] = 0;cerr << buffer << endl; // 输出接收到的消息}}
}// 线程函数实现:发送消息
void *send_message(void *args)
{ThreadData *td = static_cast<ThreadData *>(args); // 强制类型转换为 ThreadData 结构体指针string message; // 存储用户输入的消息socklen_t len = sizeof(td->server); // 服务器地址的长度// 发送欢迎消息std::string welcome = td->serverip + " comming...";sendto(td->sockfd, welcome.c_str(), welcome.size(), 0, (struct sockaddr *)&(td->server), len);while (true){cout << "Please Enter@ ";getline(cin, message); // 获取用户输入的消息sendto(td->sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len); // 发送消息给服务器}
}
温馨提示
感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!
再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
相关文章:

【探索Linux】—— 强大的命令行工具 P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
阅读导航 引言一、UDP协议二、UDP网络程序模拟实现1. 预备代码⭕makefile文件⭕打印日志文件⭕打开指定的终端设备文件,并将其作为标准错误输出的目标文件描述符 2. UDP 服务器端实现(UdpServer.hpp)3. UDP 客户端实现(main函数&a…...

【MATLAB源码-第165期】基于matlab的科莫多巨蜥算法(KMA)机器人栅格路径规划,输出做短路径图和适应度曲线。
操作环境: MATLAB 2022a 1、算法描述 科莫多巨蜥算法(Komodo Mlipir Algorithm,简称KMA)是一种受到印尼科莫多岛上独特生物——科莫多巨蜥启发的创新算法。尽管这个算法的名称听起来很有趣,但实际上它并不是一个公认…...

【Linux】项目部署CPU彪高如何定位
1.查看所有CPU占比 使用top指令获取彪高进程的PID 2.输出进程的信息 ps H -eo pid,tid,%cpu | grep 1313 3.查看线程的信息 jstack tid nid都是十六进制的 4.进制转换 将 tid的十进制转为十六进制 找到nid 可以定位到具体位置 5.关闭程序 ps -ef | grep java kill -9 jav…...

第十二届蓝桥杯大赛软件赛决赛C/C++ 研究生组-纯质数
直接判断数据过大 相对而言,由2,3,5,7组成的数更少,则先筛选出由2,3,5,7组成的数,再判断这些数中的质数个数即可 #include <iostream> using namespace std; int main() {printf("1903");…...
MyBatis面试简答题
以下是一份MyBatis的高难度简答题,共20题: 请解释MyBatis中#{}和${}的区别,并举例说明它们在实际应用中的使用场景。 MyBatis的Mapper接口是如何与XML映射文件关联的? 如何在MyBatis中实现动态SQL?请列举几种常见的动态SQL元素并解释其作用。 描述MyBatis中的ResultMap的作…...
lua 中的元表
a{ age0, __tostringfunction() { }, __callfunction() { }, } b{} a.__indexa{}//将a表中的__index指向自己 setmetatable(a,b)//将b设置为a的元表; __tostring 当子表a被当做字符串使用时会调用原表b中的__tostring方法, __call 当子表a被当做字符串使用时…...

c语言综合练习题
1.编写程序实现键盘输入一个学生的学分绩点 score(合法的范围为:1.0—5.0),根据学生的学分绩点判定该学 生的奖学金的等级,判定规则如下表所示。 #include <stdio.h>int main() {float score;printf("请输入学生的学分…...

相机拍照与摄影学基础
1.相机拍照 相机可能形状和大小不同,但基本功能相同,包括快门速度、光圈和感光度,这些是摄影的通用概念。即使是一次性相机也是基于这三个理念工作的。不同类型相机在这三个概念上的唯一区别是你可以控制这些功能的程度。这三个参数被称为相…...
Pytorch:torch.cuda.empty_cache()
torch.cuda.empty_cache() 原理 torch.cuda.empty_cache() 是PyTorch中用来释放未被分配的缓存的内存的函数。在使用GPU进行计算时,CUDA会在内部维护一个内存缓存池,以便更快地分配和释放。但有时候,这些缓存的内存在不再需要的时候&#x…...

Linux--gdb调试
一.安装gdb sudo apt install gdb 二.使用gdb 三.gdb的相关操作 gdb 可执行文件名 显示代码: l 加断点: b 行号 启动程序:r(运行之前一定要加断点) 查看断点信息: info break/info b 删除断点信息:delete 断点编号 单步执行:n 打印 :p 显示:display 变量名: 退出:q …...

JavaSE(上)-Day6
JavaSE(上)-Day6 数组数组的定义数组的初始化打印数组分析数组索引数组内存图 方法方法的定义和调用方法的重载方法的内存图 二维数组二位数组的创建和初始化二维数组的内存图 数组 1.数组是一种容器,可以一次存储多个相同类型的数据 数组的…...

(二十五)Flask之MTVMVC架构模式Demo【重点:原生session使用及易错点!】
目录: 每篇前言:MTV&MVC构建一个基于MTV模式的Demo项目:蹦出一个问题: 每篇前言: 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领…...

[ C++ ] STL---list的使用指南
目录 list简介 list的常用接口 构造函数 赋值运算符重载 迭代器 容量相关接口 元素访问接口 修改相关接口 头插push_front() 头删pop_front() 尾插push_back() 尾删pop_back() insert() erase() list的迭代器失效 list简介 1. list是可以以O(1)的时间复杂度在任意…...

数据可视化-ECharts Html项目实战(2)
在之前的文章中,我们学习了如何创建简单的折线图,条形图,柱形图并实现动态触发,最大最小平均值。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下…...
【Network Management】DCM模块唤醒网络是主动唤醒还是被动唤醒
目录 前言 正文 1.CanNm的状态机分析 2.ComM的状态机分析 3.诊断报文唤醒网络知识扩展...
yum repolist命令的介绍
yum repolist 命令在基于 Red Hat 的 Linux 发行版中用于列出当前配置的 YUM 仓库中所有可用的软件包及其版本信息。这个命令会从本地缓存中获取软件包的索引信息,并显示所有软件包的名称和版本号,而不会实际安装或更新任何软件包。 具体来说,…...
【日志分析】Android 运营商名称显示优先级(AlphaTag/SPN)
规则说明 MTK平台的设计,优先级:(MD)CIEV > Eons > Nitz > xml 功能代码说明 【笔记】Android Telephony 漫游SPN显示定制(Roaming Alpha Tag)-CSDN博客 日志分析 关键字:lookupOpe…...
ocp考试是中文还是英文?ocp认证好考吗
ocp认证是中文还是英文考试ocp认证的考试常用语种是英文,除开英文之外还有日语等语种,但是目前没有中文(12c的时候有过中文考试),所以考生最好具有一定的英语水平再报名参加考试,ocp认证考试的形式为机试,考试的题型全…...

python问题:vscode切换环境,pip安装库网络错误,不使用anaconda安装库
python问题:vscode切换环境,pip安装库网络错误 vscode切换环境pip安装库网络错误 不使用anaconda安装库 记录一下遇见的python问题。 vscode切换环境 在vscode上面的搜索框输入 > select interpreter然后选择需要的环境。 pip安装库网络错误 用…...

理财第一课:炒股词典
文章目录 基础代码规则委比委差量比换手率市盈率市净率 短线操作散户亏钱的原因庄家分析炒股战法波浪理论其它 钱者,人生之大事,死生存亡之地,不可不察也。耕田之利,十倍;珠玉之赢,百倍;闹革命&…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
大模型真的像人一样“思考”和“理解”吗?
Yann LeCun 新研究的核心探讨:大语言模型(LLM)的“理解”和“思考”方式与人类认知的根本差异。 核心问题:大模型真的像人一样“思考”和“理解”吗? 人类的思考方式: 你的大脑是个超级整理师。面对海量信…...