当前位置: 首页 > news >正文

一套rk3588 rtsp服务器推流的 github 方案及记录 -01

我不生产代码,我只是代码的搬运工,相信我,看完这个文章你的图片一定能变成流媒体推出去。
诉求:使用opencv拉流,转成bgr数据,需要把处理后的数据(BGR)编码成264,然后推流推出去,相当于直播(实时编码)

播放器

超低延迟的RTSP播放器
https://github.com/tsingsee/EasyPlayer-RTSP-Win

青犀的一个播放器,直接下他的EasyPlayer-RTSP-Win用来测试就行。划重点,超低延时,我整体方案的延时大概是600-700ms,使用海康相机,rtsp拉流,做了yolo处理,再推出去,有编码,有解码,vlc的延时设置低了就回卡帧,Gop已经改成5了还是卡帧,没有测试Gop改成1的情况,但是vlc的延时和流畅,整体看是不太兼容的。ffmpeg使用nobuffer也会卡帧。直观感受卡的就是Gop的P帧。

服务器

live555 方案

如果你不着急的话。。。 可以试试这个方案,这方面的参考文献给列下面了,因为确实正经研究了几天还看了不少代码,认真想了应该怎么处理,但是确实不太想写,而且对我的需求来讲live555冗余了很多功能,再加上网上确实没有写好的,我又很着急要结果,确定方案能用,所以也没有用这个方案。

官方demo

live555自己的测试文件是有推流demo的,主要是根据实时需求推264文件,以及无脑做一个推264文件的服务器,当时看代码的时候一头雾水加上着急,也没太认真看,主要在live555\testProgs下面,testOnDemandRTSPServer,testH264VideoStreamer ,第二个是无脑推,第一个是你来一个请求,我从头开始给你播放一次视频文件。
这个东西的底层是向一个fTo指针里面拷贝264码流。
如果你Cpp、coding能力强的话,应该是能看懂直接改的,也就不用往后看了。

参考demo 零声 usb相机推流

网上基本上和我需求最接近的live555方案下的代码是国内的做音视频开发教学的一个零声出的视频还有他们传的这个代码。

主要功能是 v4l2相机读取mjpeg,然后ffmpeg的avcodec相关库编码,然后送live555,然后推实时流,像是改的testOnDemandRTSPServer,结构很清晰,除了不能用我也找不到原因外都挺好的。另外他的课是5K的,有点贵。

视频的话去B站带关键词,基本都能搜到,这个代码我加了那个联系QQ要到的。但是在我本地没有推成功,我也不确定是哪里的问题,编译过了,放在这里
https://gitee.com/qingfuliao/v4l2_ipc_live555?_from=gitee_search

在我这是下面这个demo 实现了一个相似的功能,编译实测是可以读取usb相机然后推流成功的。但是代码结构没有上面那个清晰。

参考demo

https://github.com/mpromonet/v4l2rtspserver

这个功能是基于linux的v4l2,使用264的方式读取相机视频流(如果你的usb相机不支持264输出,会驱动失败),然后直接拆帧把流发出去
需要自己下一个libv4l2cpp的代码放进来就能编译了

这个现在看稍微改一改就能用了,不过当时对整体没有概念,改了一阵子不知道怎么下手把我自己的码流变成demo的输入,码流送进去了但是没有推成功,定位了一会儿很难定位问题,也就搁置了。有兴趣的可以基于这个改一改。

https://blog.csdn.net/qq_43418269/article/details/122488866

这个方案我是成功了的,不过延时不太能满足我的需求,这个复现很快。他是用一个管道文件做的,我把编码之后264文件直接写到live555的testOnDemandRTSPServer.cpp这边的读取文件里面,然后逻辑是live555这边接收到请求,创建管道,相机程序初始化后阻塞住,管道被创建后往管道里写,然后另一边就开始播。。

这个就相当于是运行在一个demo里的两个程序。流倒是推出来了,只不过,我这样实现,延时很大,他说的百毫秒量级我做不到,我是2s左右。感觉也可能是我操作不当。

https://blog.csdn.net/lifexx/article/details/52823777

live555读文件改为内存读取实现,确实C++不太行,这个文章对我理解Live555,还有改成内存中的数据方向给了很大启发,但是没有按照他的做,而且他的参考代码无法运行。对我理解另一个推相机的demo有帮助

其他开源服务器框架

这个也是一个很容易就编译成功的服务器,可以使用这个做服务器,然后调用ffmpeg推流,在RK3588上也推成功了,基本没改make相关的配置,需要按照他给的快速开始流程使用git下附加库,功能很强大,但是对我的需求来讲,这个功能我进行二次开发比较慢。不排除我太菜。
https://github.com/ZLMediaKit/ZLMediaKit/tree/master

这里写这个的主要原因是他的一些文章对我的启发和快速上手有很大的参考意义,比如下面这个。

https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E6%80%8E%E4%B9%88%E6%B5%8B%E8%AF%95ZLMediaKit%E7%9A%84%E5%BB%B6%E6%97%B6%EF%BC%9F

RK3399 参考

网上有瑞芯微其他方案的rtsp推流,我只能帮忙排除错误选项
https://t.rock-chips.com/forum.php?mod=viewthread&tid=749&extra=page%3D1
如果你是在看这个帖子,可以不用看了,这个猫头的代码虽然推出去了,但是他的Rtsp是调库,这个库是闭源的,3588没有,这个网站注册要两三天才能通过,不必等这个,用不了。

rtsp推流

在github上搜索rtsp,排名最高的那个结果,就是那个小乌龟,

https://github.com/PHZ76/RtspServer
这个功能比较单一,但是足够满足我的需求了,他还使用他自己的库做了一个windows下的应用,windows上编译成功了,但是不太好用,不过对我理解他的Demo运行有一定帮助。因为用的是一套库。另外他主页还有一个rtmp ,我没进去看也没试能不能用。

https://github.com/PHZ76/DesktopSharing

在这里插入图片描述

下载安装

下载下来直接在3588上面make就可以,编译的是RtspServer-master/example里面的main 文件,这里的rtsp_h264_file.cpp是可以直接推运行推264文件的,一般不需要修改就能直接用,如果不能用,有可能是554端口被占用,改一个大点的就好了

    std::string suffix = "live";std::string ip = "127.0.0.1";std::string port = "5543";// 改这里 不要改那个"0.0.0.0" 那个是对的不用改std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;

然后rtsp_pusher.cpp还有rtsp_server.cpp都把发送文件的部分注释掉了,需要结合h264那个文件来对比把264码流写进去。

运行测试

编译出来之后运行 ./rtsp_h264_file ./test.264 就能推出来了
工程已经被我魔改过了,重新生成一个sample 来演示下结果
这是RK3588 服务器
在这里插入图片描述

这是VLC的界面IP
在这里插入图片描述

下面的是显示的结果
在这里插入图片描述

改cmake 支持opencv 、rknn,mpp

因为我使用的RKNN之间是在Qt里面编译的,工程使用的都是Cmake的cmakelists,他的makefile也不难改,主要的问题是我自己写的解码器,在使用makefile指定mpp库之后编译出来的mpp库运行不正常,具体报错找不到了,然后我qt上用是没问题的,定位到是makefile没写好,改成cmakelist就可以正常编译了
-g是为了支持gdb调试,配合我的vscode 调试配置文件,可以单步调试,全程在板上编译,没配置交叉编译环境

cmake_minimum_required(VERSION 3.5)
project(rtspserver)
set(CMAKE_INCLUDE_CURRENT_DIR ON)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSOCKLEN_T=socklen_t -g ")find_package(OpenCV 4.5.5 REQUIRED)
find_package(OpenSSL REQUIRED)# MPP
set(MPP_PATH /home/orangepi/code/mpp-develop/inc)
set(MPP_LIBS /home/orangepi/code/mpp-develop/mpp/librockchip_mpp.so)
include_directories(${MPP_PATH})# OSAL
set(OSAL_PATH /home/orangepi/code/mpp-develop/osal/inc/ /home/orangepi/code/mpp-develop/utils)
set(OSAL_LIBS /home/orangepi/code/mpp-develop/osal/libosal.a /home/orangepi/code/mpp-develop/utils/libutils.a)
include_directories(${OSAL_PATH})# RKNN lib
set(RKNN_API_PATH ${CMAKE_SOURCE_DIR}/lib)
set(RKNN_RT_LIB ${RKNN_API_PATH}/aarch64/librknnrt.so)
include_directories(${RKNN_API_PATH}/include)
include_directories(${CMAKE_SOURCE_DIR}/3rdparty)# RGA
set(RGA_PATH ${CMAKE_SOURCE_DIR}/3rdparty/rga/RK3588)
set(RGA_LIB ${RGA_PATH}/lib/Linux/aarch64/librga.so)
include_directories(${RGA_PATH}/include)aux_source_directory(src/xop SOURCE1)
aux_source_directory(src/net SOURCE2)include_directories(    src    src/xopsrc/netsrc/3rdpart)# add_executable(rtsp
# example/rtsp_server.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rtsp ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )
# add_executable(rh264
# example/rtsp_h264_file.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rh264 ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} OpenSSL::SSL OpenSSL::Crypto )
add_executable(sample
example/sample.cpp
${SOURCE1}
${SOURCE2}
src/3rdpart/md5/md5.hpp
)
target_link_libraries(sample ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS}  ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )
代码修改

代码是基于他的rtsp_server来修改的,主要修改的内容是sendFrameThread,大概思路是这样的,还差一个问题,怎么把你的原始mat图像转成264码流

bool IsKeyFrame(const char* data, uint32_t size)
{if (size > 4) {//0x67:sps ,0x65:IDR, 0x6: SEIif (data[4] == 0x67 || data[4] == 0x65 || data[4] == 0x6 || data[4] == 0x27) {return true;}}return false;
}void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients)
{       encoder e;//  encoder相关 内存拷贝int size = 0;char* buffer ;// 编码标志位int i = 0;// 生成图像int width = 1920;int height = 1080;cv::Mat colorBar= cv::Mat::zeros(height, width, CV_8UC3);// 设置彩条的宽度int barWidth = width / 8; // 8个彩条,你可以根据需要调整// 生成彩条for (int i = 0; i < 8; ++i) {// 计算彩条的起始和结束位置int startX = i * barWidth;int endX = (i + 1) * barWidth;// 设置彩条颜色(BGR格式)cv::Vec3b color;if (i % 2 == 0) {color = cv::Vec3b(255, 0, 155); // 蓝色} else {color = cv::Vec3b(0, 255, 0); // 绿色}// 在colorBar上画出彩条colorBar(cv::Rect(startX, 0, barWidth, height)) = color;}while(1){if(clients > 0) /* 会话有客户端在线, 发送音视频数据 */{{     xop::AVFrame videoFrame = {0};// printf("width is %d, height is %d",colorBar.rows,colorBar.cols);// 编码 发包if(0==i){// 第一帧有sps信息 给他两帧拼一起char *buffer1;int size1;e.init(buffer1,size1);videoFrame.size = size1;e.postAframe(colorBar,buffer,size);videoFrame.size += size;					videoFrame.buffer.reset(new uint8_t[videoFrame.size]);memcpy(videoFrame.buffer.get(), buffer1, size1);memcpy(videoFrame.buffer.get()+size1, buffer, size);i++;}		else{e.postAframe(colorBar,buffer,size);videoFrame.size = size;  // 视频帧大小 videoFrame.buffer.reset(new uint8_t[videoFrame.size]);memcpy(videoFrame.buffer.get(), buffer, videoFrame.size);}videoFrame.type = IsKeyFrame(buffer, size) ? xop::VIDEO_FRAME_I : xop::VIDEO_FRAME_P;// videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳// writeCharPointerToFile((char *)videoFrame.buffer.get(), videoFrame.size,  "filename.txt");		rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全/*//获取一帧 H264, 打包xop::AVFrame videoFrame = {0};videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)videoFrame.size = video frame size;  // 视频帧大小 videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳videoFrame.buffer.reset(new uint8_t[videoFrame.size]);                    memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size);					rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全*/}{				/*//获取一帧 AAC, 打包xop::AVFrame audioFrame = {0};audioFrame.type = xop::AUDIO_FRAME;audioFrame.size = audio frame size;  /* 音频帧大小 audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳audioFrame.buffer.reset(new uint8_t[audioFrame.size]);                    memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size);rtsp_server->PushFrame(session_id, xop::channel_1, audioFrame); // 送到服务器进行转发, 接口线程安全*/}		}// xop::Timer::Sleep(20);  /* 实际使用需要根据帧率计算延时!  我这里处理延时很大,就不人工延迟了*/}videocapture->release();e.deinit((MPP_RET)0);yolo5.deinit();}

rk3588编码

这方面网上的文章不太多,但是官方给了demo,都是中文,认真看看,功能都是能用的。
主要参考他的mpp-develop/test/mpi_enc_test 以及Rk3588-linux-v002\linux\docs\Linux\Multimedia\Rockchip_Developer_Guide_MPP_CN.pdf进行配置和使用。这相关的东西我之后再另开一个文章单独说,总之参考这部分可以做一个BGR888转成264存储的demo。
这里重点说一个概念,I、P、B帧
这个东西是264流编码的一个概念,正常你每一帧的图像都很大,比如一个1920*1080,每个像素点存一个BGR888的话,就是1920*1080*3 Byte =6220800 Byte ≈ 6M ,然后一秒30帧的话,一秒就要传180M,局域网或许勉强可以,但是对带宽压力也很大。所以这里就涉及到了压缩,264、265就是压缩标准,压缩中需要做两种压缩 帧内压缩帧间压缩

  • 帧内压缩:使用一定方法使用尽量小的空间存一帧数据。

  • 帧间压缩:利用帧和前后帧的关联来进一步的压缩视频。

这里我们重点关注帧间压缩。给一个参考文献
https://zhuanlan.zhihu.com/p/409527359
说的挺透彻的,这里我粗略说一下,看下面这个图
在这里插入图片描述

I帧 ,是帧间压缩里面的一帧完整图像,P帧是前向预测帧,B帧是双向预测帧
IDR帧是特殊的I帧,在编解码时候P、B帧可以参考I帧前面的帧进行复原,但是不能参考IDR帧前面的帧进行复原

而一个上面这样的循环,被编码成一组,我们指定了h264的gop大小,就确定了多少帧中有一个I帧
而我们在做直播,就导致为了低延时,不要B帧,gop 也要尽量的不要太大,如果要解码P帧,前面就一定要缓存I帧,

监测工具

wireshark, 这个感觉还是蛮必要的,至少你能看见客户端和服务器之间说没说话。如果你有耐心开RTSP 或者网络协议握手说明的话,你甚至能看到他们之间的握手流程。

杂记

中间遇到了一个问题,因为我这个地方没有公网,所以只能自己给开一个热点给电脑,PC和RK3588之间通过路由器连接,然后使用前面的某个demo的时候遇到的,主机向服务器(RK3588)发出视频请求时,服务器并没有直接给客户端发rtcp包,而是给一个200多的地址发包,而这个包在客户端收不到,但是他能收到rtp的协议包,所以vlc这边也不提示打不开,就是没有图像显示。
后来使用的方法是,和板子通过路由器网线连接,然后电脑PC wifi 连接路由器,然后路由器没有公网,再使用一个手机usb给电脑共享网络,让我的调试环境稳定可以接受到3588的流,和路由器网线连接的时候接受不到包,感觉是因为路由器没有网,使用网线连接时候被屏蔽了服务器功能,所以交给路由器的包转发请求没有被PC识别到,但是wifi连接的话,就算他没有网,也是不能忽略的。 目前是这样理解的。

相关文章:

一套rk3588 rtsp服务器推流的 github 方案及记录 -01

我不生产代码&#xff0c;我只是代码的搬运工&#xff0c;相信我&#xff0c;看完这个文章你的图片一定能变成流媒体推出去。 诉求&#xff1a;使用opencv拉流&#xff0c;转成bgr数据&#xff0c;需要把处理后的数据&#xff08;BGR&#xff09;编码成264&#xff0c;然后推流…...

PyQt6 QComboBox下拉组合框控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计34条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…...

常用类与比较器

常用类 学一个类&#xff0c;先搞清楚继承关系&#xff0c;再看源码 包装类Wrapper jdk5之前是手动装箱拆箱 jdk5及之后是自动装箱拆箱&#xff08;调用valueOf方法&#xff08;自动默认&#xff09;/创建对象的构造方法&#xff0c;XXXvalue方法…...

【上海大学《面向对象程序设计A》课程小项目报告】抽象向量类模板及其派生类

1 项目内容及要求 本项目通过设计一个抽象向量类模板&#xff0c;以及一个通用的向量类模板和一个字符串类作为其派生类&#xff0c;以满足各种应用场景中的数据存储和处理需求。 项目内容&#xff1a; 抽象向量类模板。派生向量类。派生字符串类。测试及异常处理。联合测试…...

Leetcode每日一题学习训练——Python3版(到达首都的最少油耗)

版本说明 当前版本号[20231205]。 版本修改说明20231205初版 目录 文章目录 版本说明目录到达首都的最少油耗理解题目代码思路参考代码 原题可以点击此 2477. 到达首都的最少油耗 前去练习。 到达首都的最少油耗 ​ 给你一棵 n 个节点的树&#xff08;一个无向、连通、无环…...

Java面试题(每天10题)-------连载(42)

目录 Spring篇 1、Spring Bean的作用域之间有什么区别&#xff1f; 2、什么是Spring inner beans&#xff1f; 3、Spring框架中的单例Beans是线程安全的吗&#xff1f; 4、请举例说明如何在Spring中诸如一个Java Collection&#xff1f; 5、如何向Spring Bean中诸如一个J…...

netty websocket学习

【硬核】肝了一月的Netty知识点 超详细Netty入门&#xff0c;看这篇就够了&#xff01; bzm_netty_sb netty-chat vuewebsokect实现实时聊天&#xff0c;可单聊、可群聊&#xff08;一&#xff09; vue实现聊天栏定位到最底部&#xff08;超简单、可直接复制使用&#xff09;…...

【数据结构】环形队列

环形队列 1. 定义 环形队列就是将队列在逻辑上看作环形结构、物理上仍是数组形式存储的一种数据结构。 其实现主要分为两种情况&#xff1a; 浪费空间法记录空间法 2. 实现 实现要考虑的是成员变量 2.1 记录空间法 使用used标识当前存储了多少元素&#xff0c;如果为空&a…...

嵌入式C编码规范

嵌入式C编码规范 编码规范&#xff0c;没有最好&#xff0c;只有最合适&#xff0c;有但不执行不如没有。 嵌入式C编码规范 https://mp.weixin.qq.com/s/z4u3YnF6vdQ1olsLeF-y_A 更多嵌入式信息请关注微信公众号【嵌入式系统】...

Golang 并发 — 流水线

并发模式 我们可以将流水线理解为一组由通道连接并由 goroutine 处理的阶段。每个阶段都被定义为执行特定的任务&#xff0c;并按顺序执行&#xff0c;下一个阶段在前一个阶段完成后开始执行。 流水线的另一个重要特性是&#xff0c;除了连接在一起&#xff0c;每个阶段都使用…...

Elasticsearch:什么是非结构化数据?

非结构化数据定义 非结构化数据是指未按照设计的模型或结构组织的数据。 非结构化数据通常被归类为定性数据&#xff0c;可以是人类或机器生成的。 非结构化数据是最丰富的可用数据类型&#xff0c;经过分析后&#xff0c;可用于指导业务决策并在许多其他用例中实现业务目标。…...

15:00的面试,15:06就出来了,问的问题过于变态了。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…...

Web自动化测试怎么做?Web网页测试全流程解析

1、功能测试 web网页测试中的功能测试&#xff0c;主要测试网页中的所有链接、数据库连接、用于在网页中提交或获取用户信息的表单、Cookie 测试等。 &#xff08;1&#xff09;查看所有链接&#xff1a; 测试从所有页面到被测特定域的传出链接。 测试所有内部链接。 测…...

MySQL数据库SQLSTATE[22007]: Invalid datetime format 日期类型不能为空值的解决办法

如果你的数据库是mysql&#xff0c; 如果你创建表或插入数据时遇到的BUG–它长这样&#xff1a; Invalid datetime format: 1292 Incorrect datetime value: ‘’ for column ‘xxx’ at row 1 或 1067 - Invalid default value for ‘xx’ 那么我将赐予你 两套剑法: &#…...

搬运工让你分分钟了解Web接口测试

01、什么是接口 百度说&#xff1a;接口泛指实体把自己提供给外界的一种抽象化物&#xff08;可以为另一实体&#xff09;&#xff0c;用以由内部操作分离出外部沟通方法&#xff0c;使其能被内部修改而不影响外界其他实体与其交互的方式 上面这句有点抽象&#xff0c;网上的…...

作业12.5

1.定义一个基类 Animal&#xff0c;其中有一个虛函数perform&#xff08;)&#xff0c;用于在子类中实现不同的表演行为。 #include <iostream>using namespace std; class Animal { private:int weight; public:Animal(){}Animal(int weight):weight(weight){}virtual …...

leetCode 47. 全排列 II + 回溯算法 + 图解 + 笔记

给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]] 示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2…...

Maya 2024(3D建模、动画和渲染软件)

Maya 2024是一款非常强大的3D建模、动画和渲染软件&#xff0c;它提供了许多新功能和改进&#xff0c;以帮助建模师、动画师和渲染师更加高效地进行创作。 在建模方面&#xff0c;Maya 2024引入了Symmetry&#xff08;对称&#xff09;功能&#xff0c;可以在网格两侧生成均匀…...

C++作业5

完成沙发床的多继承&#xff08;有指针成员&#xff09; 代码&#xff1a; #include <iostream>using namespace std;class Bed { private:double *money; public:Bed(){cout << "Bed::无参构造函数" << endl;}Bed(double money):money(new doub…...

Go语言很难吗?为什么 Go 岗位这么少?

其实这个话题已经躺在我的 TODO 里很久了&#xff0c;近来很多社区的小伙伴都私下来交流&#xff0c;也有在朋友圈看吐槽 Go 上海的大会没什么人。还不如 Rust 大会&#xff0c;比较尴尬。 今天主要是从个人角度看看为什么 Go 岗位看起来近来很难的样子&#xff1f; 盘一下数…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...