计算机网络(3) --- 网络套接字TCP
计算机网络(2) --- 网络套接字UDP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131977544?spm=1001.2014.3001.5501
目录
1.TCP
1.服务端接口介绍
1.listen状态
2.accept获取链接
2.客户端接口介绍
2.TCP的服务器和客户端接口实现
1.服务端
1.成员函数
2.接口
start()实现方式
1.单一执行流
2.多进程
3.多线程
4.线程池
3.main函数
2.客户端
1.成员函数
2.接口
3.mian函数
3.守护进程化
1.守护进程
2.代码
1.TCP
回顾一下UDP套接字,实现很简单,只需要初始化然后再send即可。但是TCP更加复杂
1.服务端接口介绍
1.listen状态
listen状态适用于获取先链接的,第二个参数不能填太大的int类型数据。
2.accept获取链接
服务器只有先accept获取新链接(客户端传来的套接字),才能接受到套接字。
1.调用成功返回一个文件描述符, 失败返回-1。这个返回值其实对应的是一个套接字。
2.第一个sockfd其实是接收用的套接字,它不参与到具体的操作内;而返回值返回的套接字才是客户端返回的套接字,这个套接字是用于处理的。
3.由于tcp是面向字节流的,所以接受到的套接字就可以使用read和write进行操作了
4.如果该套接字使用完毕,一定要释放(close)套接字。因为文件描述符的本质是数组,而数组有一定的上限,我们不能只入而不释放,如果不释放会出现文件描述符泄漏。
2.客户端接口介绍
1.connect:发起链接
链接对应服务端的ip和port,表示自己要链接哪个服务端
2.TCP的服务器和客户端接口实现
1.服务端
namespace Server {enum{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR,LISTEN_ERR,OPEN_ERR};static const uint16_t gport = 8080;static const int gbacklog = 5;class tcpServer{public:tcpServer(const uint16_t &port = gport): _listensock(-1), _port(port){}void initServer(){// 1.创建_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){logMessage(FATAL, "create listensock error");exit(SOCKET_ERR);}logMessage(NORMAL, "create listensock success");// 2.bindstruct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;if (bind(_listensock, (struct sockaddr *)&local, sizeof local) < 0){logMessage(FATAL, "bind error");exit(BIND_ERR);}logMessage(NORMAL, "bind listensock success");// 3.设置socket,为监听状态if (listen(_listensock, gbacklog)){logMessage(FATAL, "listen error");exit(LISTEN_ERR);}logMessage(NORMAL, "listen listensock success");}void start(){for (;;){// 单线程版,只能有一个执行流,其他的无法进入执行,因为serviceIO死循环// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// sock是面向字节流的,后续全部都是文件操作serviceIO(sock);close(sock); //不释放会出现文件描述符泄漏}}void serviceIO(int sock){char buffer[1024];while (true){ssize_t n = read(sock, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;std::cout << "recv message: " << buffer << std::endl;std::string outbuffer = buffer;outbuffer += "server[echo]";write(sock, outbuffer.c_str(), outbuffer.size());}else if (n == 0){// 代表client退出logMessage(NORMAL, "client quit,me too");break;}}}~tcpServer(){}private:uint16_t _port;int _listensock; // 不是用来通信的,而是用于监听链接的}; }
1.成员函数
uint16_t _port:端口号
int _listensock:监听套接字
2.接口
1.initServer()创建套接字,先初始化监听套接字;生成对应的监听套接字;随后将当前的IP设置为任意IP,并且设置port最后绑定(bind)起来;随后还需要listen监听套接字
2.start()先定义新套接字,accept获取新套接字,执行套接字传输的任务。
start()实现方式
1.单一执行流
void start(){for (;;){// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// sock是面向字节流的,后续全部都是文件操作serviceIO(sock);close(sock); //不释放会出现文件描述符泄漏}}
这样的缺点很明显:只有一个执行流操作服务端,也就意味着客户端只有一个能链接服务端。而且serviceIO()是一个死循环函数,那么只有客户端主动退出才能让其他客户端链接。这是串行的执行逻辑
2.多进程
1.信号版void start(){signal(SIGCHLD, SIG_IGN);for (;;){// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// 多进程pid_t id = fork();if (id == 0){// childclose(_listensock);serviceIO(sock);close(sock);exit(0);}close(sock);}}
1.直接忽略子进程阻塞的状态,这样操作系统会自动回收
2.只要子进程自动回收,那么父进程就不需要等待,直接不断的按照需求新建子进程,而子进程执行结束不需要管理也不会有内存泄漏问题
3.在父进程处close(sock)的做法是为了不让文件描述符泄漏,子进程的close不影响父进程,如果父进程不弄,子进程把自己的套接字关闭不代表父进程的套接字也被关闭了
2.waitpid版void start(){for (;;){// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// 多进程pid_t id = fork();if (id == 0){// childclose(_listensock);if (fork() > 0)exit;// 孙子进程变为孤儿进程serviceIO(sock);close(sock);exit(0);}close(sock);// fatherpid_t ret = waitpid(id, nullptr, 0); //子进程进去直接死亡回收,不需要管理if (ret > 0)std::cout << "wait success: " << ret << std::endl;}}
1.父进程先非阻塞等待
2.子进程中创建孙子进程,孙子进程执行接收的文件,子进程直接退出,让父进程回收。此时孙子进程变成孤儿进程托付给操作系统,操作系统管理孙子进程的结束。
多进程展现的问题就是消费太多资源,本来一个执行流能解决的事情却创造了调度执行流的基本单位进程来实现,而且拷贝需要时间,成本过大。
3.多线程
class ThreadData{public:ThreadData(tcpServer *self, int sock): _self(self), _sock(sock){}public:tcpServer *_self;int _sock;};void start(){for (;;){// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// 多线程pthread_t tid;ThreadData *td = new ThreadData(this, sock);pthread_create(&tid, nullptr, threadRoutine, td);}}static void *threadRoutine(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);td->_self->serviceIO(td->_sock);delete td;close(td->_sock);return nullptr;}
1.创造线程,让子线程进行接收执行。当然为了不需要串行执行,在threadRoutine()中,优先将当前线程进行线程分离。这样主线程就不需要回收子线程,子线程结束操作系统就会自动回收。
2.执行后需要将当前的文件描述符回收,由于函数是线程的公共资源,所以threadRoutine内就能影响到。
4.线程池
//线程池 using namespace ThreadNs;const int gnum = 10;template <class T> class ThreadPool;template <class T> class ThreadData { public:ThreadData(ThreadPool<T> *tp, const std::string &n): threadpool(tp), name(n){}public:ThreadPool<T> *threadpool;std::string name; };template <class T> class ThreadPool { private:static void *handlerTask(void *args){ThreadData<T> *td = static_cast<ThreadData<T> *>(args);while (true){T t;{// td->threadpool->lockQueue();LockGuard lockguard(td->threadpool->mutex());while (td->threadpool->isQueueEmpty()){td->threadpool->threadWait();}t = td->threadpool->pop();}// td->threadpool->unlockQueue();std::cout << td->name << "处理完了任务: " << t.toTaskString() << "并处理完成,结果是: " << t();}return nullptr;}ThreadPool(const int &_num = gnum): _num(gnum){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);for (int i = 0; i < _num; i++){_threads.push_back(new Thread());}}void operator=(const ThreadPool &) = delete;ThreadPool(const ThreadPool &) = delete;public:static ThreadPool<T> *getInstance(){if (_tp == nullptr){_singleton_lock.lock();if (_tp == nullptr){_tp = new ThreadPool<Task>();}_singleton_lock.unlock();}return _tp;}// void lockQueue()// {// pthread_mutex_lock(&_mutex);// }// void unlockQueue()// {// pthread_mutex_unlock(&_mutex);// }bool isQueueEmpty(){return _task_queue.empty();}void threadWait(){pthread_cond_wait(&_cond, &_mutex);}T pop(){T t = _task_queue.front();_task_queue.pop();return t;}pthread_mutex_t *mutex(){return &_mutex;}public:void run(){for (const auto &t : _threads){ThreadData<T> *td = new ThreadData<T>(this, t->threadname());t->start(handlerTask, td);std::cout << t->threadname() << " start ..." << std::endl;}}void push(const T &in){// pthread_mutex_lock(&_mutex);LockGuard lockguard(&_mutex);_task_queue.push(in);pthread_cond_signal(&_cond);// pthread_mutex_unlock(&_mutex);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);for (const auto &t : _threads)delete t;}private:int _num;std::vector<Thread *> _threads;std::queue<T> _task_queue;pthread_mutex_t _mutex;pthread_cond_t _cond;static ThreadPool<T> *_tp;static std::mutex _singleton_lock; };template <class T> ThreadPool<T> *ThreadPool<T>::_tp = nullptr; static std::mutex _singleton_lock; /void start(){// 线程池初始化ThreadPool<Task>::getInstance()->run();for (;;){// 1.sever获取新链接struct sockaddr_in peer;socklen_t len = sizeof peer;int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;// 4.线程池ThreadPool<Task>::getInstance()->push(Task(sock, serviceIO));}}
3.main函数
using namespace std; using namespace Server;static void Usage(string proc) {cout << "Usage:\n\t" << proc << " local_ip local_port\n\n"; }int main(int argc, char *argv[]) {if (argc != 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);std::unique_ptr<tcpServer> tsvr(new tcpServer(port));tsvr->initServer();tsvr->start();return 0; }
1. 一旦启动,就会进入LISTEN状态
2.客户端
#define NUM 1024namespace Client {class tcpClient{public:tcpClient(const std::string &serverip, const uint16_t &serverport): _serverip(serverip), _serverport(serverport), _sock(-1){}void initClient(){// 1.创建socket_sock = socket(AF_INET, SOCK_STREAM, 0);if (_sock < 0){std::cerr << "socket error: " << errno << " : " << strerror(errno) << std::endl;exit(2);}// 2.client要不要bind[必须要的],client要不要显示的bind,不需要// 3.客户端不需要listen// 4.也不需要accept}void start(){// 5.要发起链接struct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_port = htons(_serverport);server.sin_addr.s_addr = inet_addr(_serverip.c_str());if (connect(_sock, (struct sockaddr *)&server, sizeof server) != 0){std::cerr << "connect error: " << errno << " : " << strerror(errno) << std::endl;}else{std::string msg;while (true){std::cout << "Enter# ";std::getline(cin, msg);write(_sock, msg.c_str(), msg.size());char buffer[NUM];int n = read(_sock, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;std::cout << "server回显的信息: " << buffer << std::endl;}else{break;}}}}~tcpClient(){if (_sock >= 0)close(_sock);}private:int _sock;std::string _serverip;uint16_t _serverport;}; }
1.成员函数
int _sock:套接字
std::string _serverip:server的IP地址
uint16_t _serverport:server发PORT2.接口
3.mian函数
static void Usage(string proc) {cout << "Usage:\n\t" << proc << " server_ip server_port\n\n"; }int main(int argc, char *argv[]) {if (argc != 3){Usage(argv[0]);exit(1);}uint16_t serverport = atoi(argv[2]);std::string serverip = argv[1];std::unique_ptr<tcpClient> tcli(new tcpClient(serverip, serverport));tcli->initClient();tcli->start();return 0; }
在同一个服务器运行客户端和服务端
1.ESTABLISHED:指的是客户端被服务端所接收了
2.tcp的Server查到的是服务器的链接
3.tcp的Client查到的是客户端的链接
4.两端都是全双工的
3.守护进程化
1.守护进程
1.xshell在操作系统下会生成一个会话,此时bash充当前台任务,其他都是后台任务
2.前台任务有且只能有一个,而后台任务能允许有多个
3.所有的作业可以前后台转换。先fg转换,再ctrl+Z切换后台暂停,最后bg使得暂停任务重新开始
4.这些任务可能受到用户的登录和注销的影响的,我们需要将作业自称独立会话,和终端设备无关,这样的进程为守护进程
1.setsid:将非组员的进程独立成一个会话,并且该进程变成此会话的组长
2.不能是原先就是组长的进程
/dev/null:黑洞文件,信息重定向到该文件默认数据全部清空丢弃。
2.代码
#define DEV "/dev/null"void daemonself(const char *currPath = nullptr) {// 1.让调用进程忽略异常信号signal(SIGPIPE, SIG_IGN);// 2.如何让自己不是组长,setsidif (fork() > 0)exit(0);// 守护进程 -- 精灵进程,孤儿进程的一种pid_t n = setsid();assert(n != -1);// 3.守护进程脱离终端,关闭或者重定向以前进程默认打开文件 012int fd = open(DEV, O_RDWR);if (fd >= 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}else{close(0);close(1);close(2);}// 4.可选:进程执行路径发生变化if (currPath)chdir(currPath); }
1.让调用进程忽略异常信号:不出现进程错误的问题使得守护过程终止
2.让自己不是组长(setsid):守护化的条件就是进程不能是会话的组长,要想不是,上面的处理方式是fork一个子进程,当前进程直接释放,使得fork的子进程变成孤儿进程,孤儿进程托付给操作系统,此时的组长是bash,那么就可以进行setsid了
3.守护进程脱离终端,关闭或者重定向以前进程默认打开文件 012:不直接关闭,将/dev/null这个黑洞文件重定向到012中。
4.可选:进程执行路径发生变化。将当前进程执行的路径换掉。
5.此时服务端的main函数逻辑为:
int main(int argc, char *argv[]) {if (argc != 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);std::unique_ptr<tcpServer> tsvr(new tcpServer(port));tsvr->initServer();// 守护进程化daemonself();tsvr->start();return 0; }
相关文章:

计算机网络(3) --- 网络套接字TCP
计算机网络(2) --- 网络套接字UDP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131977544?spm1001.2014.3001.5501 目录 1.TCP 1.服务端接口介绍 1.listen状态 2.accept获取链接 2.客户端接口介绍 2.TCP的服务器…...

大数据技术之Hadoop(二)
目录 一、Hadoop的诞生 二、大数据概述 三、大数据软件生态 3.1 数据存储相关技术 3.2 数据计算相关技术 3.3 数据传输相关技术 四、什么是Hadoop 本篇主要讲解大数据的核心概念以及Hadoop的基本介绍。 一、Hadoop的诞生 大数据的发展与日益庞大的数据量是密不可分的。从…...

运维工程师第二阶段linux基础
文章目录 linux基础1.linux发展史--前身unix2.linux特点3.linux操作系统安装4.linux基础操作5.shell与终端6.Linux基础命令使用管理员找回密码linux的目录和管理1.根目录下目录结构及作用文件类型2.基本的目录管理命令查看基本的文件管理命令重定向① 几个概念② Linux打包操作…...

ChatGPT安全技术
前言 近期,Twitter 博主 lauriewired 声称他发现了一种新的 ChatGPT"越狱"技术,可以绕过 OpenAI 的审查过滤系统,让 ChatGPT 干坏事,如生成勒索软件、键盘记录器等恶意软件。 他利用了人脑的一种"Typoglycemia&q…...

使用cmd查看3568主板相关
主要是说清楚思路的 rk3568主板能运行的程序都在system/bin里面,这个是我们直接可以使用cmd用到的 所以,往后我们想通过cmd了解RK3568的某一项参数的时候,或者想使用RK3568某一个系统功能的时候。应该先去system/bin里面查找对应的系统程序。…...

SpringBoot限制(限流)接口访问频率
限流整个流程过程 1.首先用户的请求进来,将用户ip和uri组成key,timestamp为value,放入zset 2. 更新当前key的缓存过期时间,这一步主要是为了定期清理掉冷数据,和上面我提到的常见错误设计2中的意义不同 3. 删除窗口之…...

蓝桥杯,我劝你不要参加的8个完美理由
蓝桥杯,是一个全国高校的IT技术比拼,如果你参加了,可能不止是刷题数量的剧增,还有你的软件人生 我劝你不要参加,因为如果你参加了,可能会有以下烦恼: 目录 1、会让你变得上进 2、会提前感受码…...

ChatGPT及其工作原理;OpenAI申请注册商标GPT-5,引发关注
🦉 AI新闻 🚀 OpenAI申请注册商标GPT-5,引发关注 摘要:OpenAI已在上月18日申请注册商标GPT-5,显示该模型将提供文本生成、自然语言理解、语音转录、翻译、分析等功能。此前OpenAI曾表示尚未开始训练GPT-4的后继者GPT…...

[C++项目] Boost文档 站内搜索引擎(2): 文档文本解析模块parser的实现、如何对文档文件去标签、如何获取文档标题...
项目开始的准备工作 在上一篇文章中, 已经从Boost官网获取了Boost库的源码. 接下来就要编写代码了. 不过还需要做一些准备工作. 创建项目目录 所有的项目文件肯定要在一个目录下, 找一个位置执行下面这行指令 mkdir Boost-Doc-Searcher将文档html文件, 存放到项目中 cd Boost…...

若依框架vue使用Element 如何把当前页面的所有Table表格row.id和一个表单的16个字段内容通过js传Java后台,Java后台是如何接收的
如果你使用的是Vue.js与Element UI框架,可以按照以下步骤将当前页面的所有表格行的row.id和一个表单的16个字段内容通过JavaScript传递给Java后台: 首先,在Vue组件中,使用Element UI的Table组件和Form组件来构建表格和表单。为了…...

迁移学习:使用Restnet预训练模型构建高效的水果识别模型
引言 本项目在Restnet预训练模型的基础上,通过迁移学习构建了水果分类识别模型,经过30epochs训练,实现了模型的快速收敛,准确率达到了96%以上。通过此项目实战,我们进一步熟悉了如何在预训练模型的基础上进行迁移学习…...

浅谈机器视觉
目录 1.什么是机器视觉 2.学习机器视觉需要掌握的知识 3.机器视觉的由来 4.机器视觉带来的福利 1.什么是机器视觉 机器视觉(Computer Vision)是人工智能领域中的一个分支,旨在通过模仿人类的视觉系统,使计算机能够理解和解释图…...

助力保险行业数字化创新,麒麟信安参展2023中国财险科技应用高峰论坛
2023年7月27日,由中科软科技股份有限公司主办的“中国财险科技应用高峰论坛”在北京古北水镇成功举办。作为享誉中国保险科技界的盛会,本次活动以“数智保险 创新未来”主题,汇聚全国数百位保险公司主管领导、资深保险行业信息化专家…...

eclipse was unable to locate its companion shared library
当转移或者Copy工程时, eclipse was unable to locate its companion shared library eclipse.ini 里面的路径配置错误导致 --launcher.library C:/Users/**/.p2/pool/plugins/org.eclipse.equinox. launcher.win32.win32.x86_64_1.2.700.v20221108-1024 -product …...

【MySQL】使用C/C++连接MySQL数据库
【MySQL】使用C/C连接MySQL数据库 验证使用select特殊点 本文目的:使用MySQL提供的CAPI完成对数据库的操作 验证 #include <iostream> #include <mysql/mysql.h>int main() {std::cout<<"mysql cilent version: "<<mysql_get_cl…...

【Python】从同步到异步多核:测试桩性能优化,加速应用的开发和验证
目录 测试工作中常用到的测试桩mock能力 应用场景 简单测试桩 http.server扩展:一行命令实现一个静态文件服务器 性能优化:使用异步响应 异步响应 能优化:利用多核 gunicorn 安装 gunicorn 使用 gunicorn 启动服务 性能优化&#…...

使用checkBox组件时,动态设置disabled,仍能触发click事件的原因及解决办法
在使用vant的Checkbox组件时,为了实现复选框组选择一个,禁用掉另一个,同时添加点击事件的功能时。遇到明明disabledtrue,但仍能触发点击事件的情况。为此,分析下触发点击事件的原因及解决方法。 一、原因 1、异步更新…...

【JavaScript】如何进行除法运算且保留小数部分不参与四舍五入【推荐库bignumber.js 】
在 bignumber.js 中进行除法运算并保留小数部分,不参与四舍五入,你可以使用 decimalPlaces 方法来指定保留的小数位数,并使用 ROUND_DOWN 舍入模式来实现截断而不进行四舍五入。 以下是在 bignumber.js 中进行除法运算且保留小数部分&#x…...

掌握Java JDK 1.8 API帮助文档中文版,事半功倍编程
文章目录 1. JDK 1.8 API帮助文档简介2. 如何查阅JDK 1.8 API帮助文档中文版2.1 在线文档2.2 本地文档2.3 集成开发环境(IDE) 3. 如何使用JDK 1.8 API帮助文档中文版3.1 寻找类和方法3.2 阅读文档说明3.3 查看示例代码 4. 总结 引言: Java是一…...

Spring Boot的自动配置原理
一.原理解释 Spring Boot的自动配置是Spring框架的一个重要特性,它旨在简化应用程序的开发和部署过程。自动配置通过基于类路径中的依赖关系和配置文件内容来预先配置Spring应用程序的各种组件和功能。这样,我们可以在无需显式配置大量参数的情况下&…...

NFS服务器
目录 1.nfs简介 2.nfs安装与配置简述 安装包: 配置文件: /etc/exports配置文件的写法 权限:(客户端对共享目录的权限,但是最主要的还是目录本身的权限) 3.nfs配置 服务端 客户端 4.autofs自动挂载…...

说明学习委员之作业管理系统—后端部分
项目背景 学习委员收集作业的过程,繁琐且曲折,作者充分理解并体谅为大家服务的苦逼学习委员,以此为出发点和灵感,设计并开发了此套作业管理系统,希望能帮助各位提高效率,早日摆脱重复机械式的工作…...

质数(判定质数 分解质因数 筛质数)
目录 一、判定质数思路分析代码实现 二、分解质因数思路分析典型题目代码实现 三、质数筛经典题目思路分析1. 朴素筛法2. 埃氏筛法3. 欧拉筛法 一、判定质数 思路分析 由于每个合数的因子是成对出现的,即如果 d d d 是 n n n 的因子,那么 n d \frac…...

SAP数据库表维护视图生成器的使用
在SAP中,经常需要自定义数据库表。而且可能需要人工维护数据库表中的数据,可以通过SM30进行维护数据;但是SM30事务的权限太大,不适宜将SM30直接分配;因此,可以通过给维护表分配事务代码,来达到控…...

数据结构 | 递归
目录 一、何谓递归 1.1 计算一列数之和 1.2 递归三原则 1.3 将整数转换成任意进制的字符串 二、栈帧:实现递归 三、递归可视化 四、谢尔平斯基三角形 五、复杂的递归问题 六、动态规划 一、何谓递归 递归是解决问题的一种办法,它将问题不断地分…...

微信发视频怎么不压缩画质?试试这几招
微信是我们常用的社交工具了,很多朋友都会用它跟好友分享视频,但想必大家都知道,微信为了节省宽带和存储空间,会自动对上传的视频进行压缩处理,甚至过大的视频会被限制发送,怎么才能让微信不自动压缩画质呢…...

【网络安全带你练爬虫-100练】第16练:使用session发送请求
目录 一、目标1:使用seesion进去请求 二、网络安全O 一、目标1:使用seesion进去请求 (1)应用: 通过创建会话(session)对象来请求并爬取返回的数据包 情景:需要登录才能爬取的网…...

论文代码学习—HiFi-GAN(3)——模型损失函数loss解析
文章目录 引言正文生成器损失函数最小二乘损失函数梅尔频谱图损失函数特征匹配损失函数生成器最终损失函数loss生成器loss对应代码 鉴定器损失函数鉴定器损失函数代码 总结引用 引言 这里翻译了HiFi-GAN这篇论文的具体内容,具体链接。这篇文章还是学到了很多东西&a…...

CLion中avcodec_receive_frame()问题
1. 介绍 在提取音视频文件中音频的PCM数据时,使用avcodec_receive_frame()函数进行解码时,遇到了一些问题,代码在Visual Studio 2022中运行结果符合预期,但是在CLion中运行时,获取的AVFrame有错误,和VS中获…...

Linux安装操作(Mac版本)
Parallels Desktop的简介 Parallels Desktop是Mac平台上的虚拟机软件,也是Mac平台最好的虚拟机软件之一。它允许用户在Mac OS X系统上同时运行其他操作系统,例如Windows、Linux等。Parallels Desktop为Mac用户提供了使用其他操作系统和软件的便利性&…...