《TCP/IP网络编程》阅读笔记--并发多进程服务端的使用
目录
1--并发服务器端
2--进程
2-1--进程的相关概念
2-2--fork()创建进程
2-3--僵尸进程
2-4--wait()和waitpid()销毁僵尸进程
3--信号处理
3-1--signal()函数
3-2--sigaction()函数
3--3--利用信号处理技术消灭僵尸进程
4--基于多任务的并发服务器
5--分割 TCP 的 I/O 程序
1--并发服务器端
并发服务器端主要有以下三类:
① 多进程服务器:通过创建多个进程提供服务;
② 多路复用服务器:通过捆绑并统一管理I/O对象提供服务;
③ 多线程服务器:通过生成与客户端等量的线程提供服务;
2--进程
2-1--进程的相关概念
进程的相关概念:
① 进程的定义如下:占用内存空间的正在运行的程序;
② 从操作系统的角度看,进程是程序流的基本单位,若创建多个进程,则操作系统将同时运行;
③ 对于 CPU 而言,核的个数与可同时运行的进程数相同;若进程数超过核数,进程将分时使用 CPU 资源;
④ 无论进程是如何创建的,所有进程都会从操作系统中分配到进程 ID,其值为大于 2 的整数;
2-2--fork()创建进程
#include <unistd.h>
pid_t fork(void);// 成功时返回进程 ID,失败时返回 -1
fork() 函数会复制父进程的进程副本给创建的子进程,两个进程都将执行 fork() 函数调用后的语句;具体执行的内容可根据 fork() 函数的返回值进行区分,对于父进程 fork() 函数返回子进程的进程 ID,对于子进程 fork() 函数返回 0;
// gcc fork.c -o fork
// ./fork
#include <stdio.h>
#include <unistd.h>int gval = 10;
int main(int argc, char *argv[]){__pid_t pid;int lval = 20;gval++, lval += 5;pid = fork();if(pid == 0){ // 对于子进程,fork返回0,因此执行以下内容gval += 2, lval += 2;}else{ // 对于父进程,执行以下内容gval -= 2, lval -= 2;}if(pid == 0){// 对于子进程,复制父进程的进程副本,则最初 gval = 11, lval = 25;// 执行 += 2 后,gval = 13, lval = 27;printf("Child Proc: [%d, %d] \n", gval, lval);}else{// 对于父进程,执行 -= 2后,gval = 9, lval = 23;printf("Parent Proc: [%d %d] \n", gval, lval);}return 0;
}
2-3--僵尸进程
一般进程完成工作后都应被立即销毁,但部分进行由于各种原因导致不能及时销毁,就成为了僵尸进程,其会占用系统中的重要资源;
终止僵尸进程的两种方式:① 传递参数给 exit 函数并调用 exit 函数;② main 函数中执行 return 语句并返回值;
向 exit 函数传递的参数值和 main 函数 return 语句的返回值都会传递给操作系统,而操作系统不会立即销毁子进程,直到把这些返回值传递给父进程;这种不会被立即销毁的子进程就是僵尸进程;
此外,操作系统不会主动将返回值传递给父进程;只有父进程主动发起请求时,操作系统才会将子进程的返回值传递给父进程;因此,如果父进程未主动要求获得子进程的结束状态值,操作系统就不会销毁子进程,子进程就一直处于僵尸进程状态;
// gcc zombie.c -o zombie
// ./zombie
#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[]){__pid_t pid = fork();if(pid == 0){puts("Hi, I am a child process");}else{// 父进程终止时,子进程也会被同时销毁// 本案例通过延缓父进程的终止时间,来让子进程进入僵尸进程状态printf("Child Process ID: %d \n", pid);sleep(30);}if(pid == 0){puts("End child process");}else{puts("End parent process");}return 0;
}
通过 ps au 可以观测到在父进程睡眠的时间里,子进程成为了僵尸进程(Z+状态);
2-4--wait()和waitpid()销毁僵尸进程
为了销毁僵尸子进程,父进程必须主动请求获取子进程的返回值;
父进程调用 wait() 函数 和 waitpid() 函数可以主动获取子进程的返回值;
#include <sys/wait.h>pid_t wait(int* statloc);
// 成功时返回终止的子进程 ID, 失败时返回 -1;
// 子进程的返回值会保存到 statloc 所指的内存空间// WIFEXITED() 子进程正常终止时返回 true
// WEXITSTATUS() 返回子进程的返回值
父进程调用 wait() 函数时,如果没有已终止的子进程,则父进程的程序将会阻塞,直至有子进程终止来返回值;
// gcc wait.c -o wait
// ./wait
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char* argv[]){int status;__pid_t pid = fork();if(pid == 0){return 3; // 第一个子进程返回3}else{printf("Child PID: %d \n", pid); // 第一个子进程的 IDpid = fork(); // 创建第二个子进程if(pid == 0){exit(7); // 第二个子进程返回7}else{printf("Child PID : %d \n", pid); // 第二个子进程的 IDwait(&status); // 主动请求获取子进程的返回值if(WIFEXITED(status)){printf("Chile send one: %d \n", WEXITSTATUS(status));}wait(&status); // 主动请求获取子进程的返回值if(WIFEXITED(status)){printf("Child send two: %d \n", WEXITSTATUS(status));}sleep(30); // 这时候父进程选择睡眠,子进程也不会成为僵尸进程}}return 0;
}
wait() 函数会引起程序阻塞,而 waitpid() 函数不会引起阻塞;
#include <sys/wait.h>pid_t waitpid(pid_t pid, int* statloc, int options);
// 成功时返回终止的子进程的ID(或0),失败时返回-1
// pid 表示等待终止的目标子进程的 ID,传递 -1 时与 wait() 相同,即可以等待任意子进程终止
// statloc 存放子进程返回结果的地址空间
// options 设置为 WNOHANG 时,即使没有终止的子进程,父进程也不会进入阻塞状态,而是返回 0 并结束函数
// gcc waitpid.c -o waitpid
// ./waitpid
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char *argv[]){int status;__pid_t pid = fork();if(pid == 0){sleep(15);return 24;}else{// 没有终止的子进程时,返回0,则一直循环调用waitpid()// 直到有终止的子进程来跳出循环while(!waitpid(-1, &status, WNOHANG)){sleep(3);puts("sleep 3sec.");}if(WIFEXITED(status)){printf("Child send %d \n", WEXITSTATUS(status));}return 0;}
}
3--信号处理
上述父进程调用 wait() 函数会阻塞,而调用 waitpid() 函数也必须不断调用(因为不知道子进程何时终止),这也同样会影响父进程的工作效率;
通过信号处理机制,可以解决上述问题;信号表示在特定事件发生时由操作系统向进程发送(通知)的消息;
因此可以通过注册信号,当子进程终止时,让操作系统将子进程终止的消息发送给父进程,这时候父进程才请求获取子进程的返回值;
3-1--signal()函数
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);// 第一个参数 signo 表示特殊情况信息
// 第二个参数表示特殊情况发生后,要调用的函数的地址值(指针)// 常见特殊情况
// 1. SIGALRM 表示已到调用 alarm 函数注册的时间
// 2. SIGINT 表示遇到了 CTRL+C 的情况
// 3. SIGCHLD 表示遇到了子进程终止的情况#include <unistd.h>
unsigned int alarm(unsigned int seconds);
// 返回 0 或以秒为单位的距离 SIGALRM 信号发生的所剩时间(即还剩下多长时间就会发生 SIGALRM 信号时间)
// 经过 seconds 秒后会发生 SIGALRM 信号事件
发生信号事件时,将会唤醒由于调用 sleep 函数而进入阻塞状态的进程;即:即使还没到 sleep 函数规定的事件也会被强制唤醒,而进程一旦唤醒后就不会再进入睡眠状态;
// gcc signal.c -o signal
// ./signal#include <stdio.h>
#include <unistd.h>
#include <signal.h>void timeout(int sig){if(sig == SIGALRM){puts("Time out!");}alarm(2);
}void keycontrol(int sig){if(sig == SIGINT){puts("CTRL+C pressed");}
}int main(int argc, char *argv[]){int i;signal(SIGALRM, timeout);signal(SIGINT, keycontrol);alarm(2);for(i = 0; i < 3; i++){puts("wait...");sleep(100); // 不会真的睡眠 100s,因为alarm函数会产生SIGALRM信号事件,从而唤醒进程}return 0;
}
3-2--sigaction()函数
sigaction() 函数的功能类似于 signal() 函数,但 sigaction() 更稳定;因为 signal() 函数在不同操作系统中可能存在区别,但 sigaction() 在不同 UNIX 系统中完全相同;
#include <signal.h>int sigaction(int signo, const struct sigaction* act, struct sigaction* oldact);
// 成功时返回0,失败时返回 -1
// signo 用于传递信号信息
// act 对应于 signo 的信号处理函数
// oldact 获取之前注册的信号处理函数的指针,不用时传递0struct sigaction{void (*sa_handler)(int); // 信号处理函数的指针sigset_t sa_mask; // 初始化为0int sa_flags; // 初始化为0
}
// gcc sigaction.c -o sigaction
// ./sigaction#include <stdio.h>
#include <unistd.h>
#include <signal.h>void timeout(int sig){if(sig == SIGALRM){puts("Time out!");}alarm(2);
}int main(int argc, char* argv[]){int i;struct sigaction act;act.sa_handler = timeout;sigemptyset(&act.sa_mask); // 调用sigemptyset()将sa_mask的所有位初始化为0act.sa_flags = 0; // sa_flags也初始化为0sigaction(SIGALRM, &act, 0);alarm(2);for(int i = 0; i < 3; i++){puts("wait...");sleep(100);}return 0;
}
3--3--利用信号处理技术消灭僵尸进程
// gcc remove_zombie.c -o remove_zombie
// ./remove_zombie#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>void read_childproc(int sig){int status;pid_t id = waitpid(-1, &status, WNOHANG); // 等待任意子线程结束if(WIFEXITED(status)){ // 判断子线程是否正常终止printf("Remove proc id: %d \n", id);printf("Child send: %d \n", WEXITSTATUS(status)); // 打印子线程的返回值}
}int main(int argc, char *argv[]){pid_t pid;struct sigaction act;act.sa_handler = read_childproc; // 设置信号处理函数sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, 0); // 调用sigaction(),当遇到子线程结束的信号时,调用信号处理函数pid = fork();if(pid == 0){ // 子线程执行区域puts("Hi! I'm child process");sleep(10);return 12;}else{printf("Child proc id: %d \n", pid);pid = fork();if(pid == 0){ // 另一个子线程执行区域puts("Hi! I'm child process");sleep(10);return 24;}else{int i;printf("Child proc id: %d \n", pid);for(int i = 0; i < 5; i++){puts("wait...");sleep(5);}}}return 0;
}
4--基于多任务的并发服务器
每当有客户端请求服务时,回声服务器端都创建子进程以提供服务;
使用 fork() 创建进程时,子进程会复制父进程拥有的所有资源,因此无需额外传递文件描述符;
// gcc echo_mpserv.c -o echo_mpserv
// ./echo_mpserv 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30void error_handling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}void read_childproc(int sig){__pid_t pid;int status;pid = waitpid(-1, &status, WNOHANG);printf("remove proc id: %d \n", pid);
}int main(int argc, char* argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;__pid_t pid;struct sigaction act; // 信号socklen_t adr_sz;int str_len, state;char buf[BUF_SIZE];if(argc != 2){printf("Usage : %s <port>\n", argv[0]);exit(1);}// 防止僵尸进程act.sa_handler = read_childproc; //设置信号处理函数sigemptyset(&act.sa_mask);act.sa_flags = 0;state = sigaction(SIGCHLD, &act, 0);serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 创建 tcp socketmemset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr)) == -1){error_handling("bind() error"); } if(listen(serv_sock, 5) == -1){error_handling("listen() error");}while(1){adr_sz = sizeof(clnt_adr);clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);if(clnt_sock == -1){continue;}else{puts("new client connected...");}// 每当有客户端请求服务时,clnt_sock 不为 -1// 因此会执行 fork() 函数创建子进程,并由子进程向客户端提供服务pid = fork(); if(pid == -1){close(clnt_sock);continue;}if(pid == 0){ // 子进程运行区域close(serv_sock); // 将复制过来的父进程中的服务器文件描述符销毁while((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0){write(clnt_sock, buf, str_len);}close(clnt_sock);puts("client disconnected...");return 0;}else{ // 父进程运行区域// 因为客户端的文件描述符已经复制到子进程中// 由子进程处理客户端的内容,因此父进程需要销毁客户端的文件描述符close(clnt_sock); }}close(serv_sock);return 0;
}
5--分割 TCP 的 I/O 程序
客户端通过 fork() 创建子进程,将 I/O 分割;客户端的父进程负责接收数据,额外创建的子进程负责发送数据;
分割后,不同进程分别负责输入和输出,因此客户端是否从服务器端接收完数据都可以进行传输;
// gcc echo_mpclient.c -o echo_mpclient
// ./echo_mpclient 127.0.0.1 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30void error_handling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}void read_routine(int sock, char *buf){while(1){int str_len = read(sock, buf, BUF_SIZE);if(str_len == 0) return;buf[str_len] = 0;printf("Message from server: %s", buf);}
}void write_routine(int sock, char* buf){while(1){fgets(buf, BUF_SIZE, stdin);if(!strcmp(buf, "q\n") || !strcmp(buf, "Q\n")){shutdown(sock, SHUT_WR); // 调用 shutdown 函数向服务器端传递 EOFreturn;}write(sock, buf, strlen(buf));}
}int main(int argc, char *argv[]){int sock;pid_t pid;char buf[BUF_SIZE];struct sockaddr_in serv_adr;if(argc != 3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_STREAM, 0); // 创建 tcp socketmemset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = inet_addr(argv[1]);serv_adr.sin_port = htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){error_handling("connect() error!");}pid = fork(); // 创建子进程实现 I/O 分离if(pid == 0){ // 子进程写数据到服务器端write_routine(sock, buf);}else{ // 父进程从服务器端中读取数据read_routine(sock, buf);}close(sock);return 0;
}
相关文章:
《TCP/IP网络编程》阅读笔记--并发多进程服务端的使用
目录 1--并发服务器端 2--进程 2-1--进程的相关概念 2-2--fork()创建进程 2-3--僵尸进程 2-4--wait()和waitpid()销毁僵尸进程 3--信号处理 3-1--signal()函数 3-2--sigaction()函数 3--3--利用信号处理技术消灭僵尸进程 4--基于多任务的并发服务器 5--分割 TCP 的…...
【C++】day2学习成果:引用、结构体等等。。。
1.封装一个结构体,结构体中包含一个私有数组,用来存放学生的成绩,包含一个私有变量,用来记录学生个数, 提供一个公有成员函数,void setNum(int num)用于设置学生个数 提供一个公有成员函数:void…...
QT 第五天 TCP通信与数据库
一、数据库增删改查 QT core gui sqlgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your comp…...
Java程序中常用的设计模式有哪些和该种设计模式解决的痛点
设计模式是大量程序员智慧的结晶,是优秀的代码范式,是以前那些大佬程序员的编程经验总结,非常值得学习。 在软件开发中,有许多常用的设计模式,每种模式都解决了特定类型的问题。以下是一些常见的设计模式及其简要介绍&…...
Android12之解析/proc/pid进程参数(一百六十四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
正儿八经的雅思口语盘丝洞大法学习总结(长期修改更新)针对23.9月考生
目录 开篇语 李仙童口语大法 具体体系内容 说道科技产品或者说非传统物品 part2回答八大准则 【part2回答八大准则】(一) 【part2回答八大准则】(二) 【part3回答七大准则】(一) Part 1 核心体系 …...
算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言
算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言 目录MT1260 袋鼠躲猫猫MT1261 留下来的才是幸运数MT1262 约数MT1263 最大的三位约数MT1264 完数MT1265 区间完数MT1266 完数与因子MT1267 亏数MT1268 因数的因数MT1269 区间素数MT1270 素数计算MT1271 三生质数…...
qt连接tcp通信和连接数据库
通过数据库实现学生管理系统 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//判断数据库对象是否包含了自己使用的数据库 Studemt.dbif(!db.co…...
MySQL Oracle区别
由于SQL Server不常用,所以这里只针对MySQL数据库和Oracle数据库的区别 (1) 对事务的提交 MySQL默认是自动提交,而Oracle默认不自动提交,需要用户手动提交,需要在写commit;指令或者点击commit按钮 (2) 分页查询 MySQL是直接在SQL语…...
Figma实用插件速收藏!精选19个干货插件大公开!
Figma 如今有着大量的插件,在 UI/UX 设计领域,很多工作已经不用真的从零开始做了。用好 Figma 插件,往往能让设计工作事半功倍。不过其中的插件素质差别很大,需要仔细筛选。不过如果你选择了对的插件,合理的设置&#…...
【STM32】FSMC—扩展外部 SRAM 初步使用 1
基于野火指南者《零死角玩转 STM32F103—指南者》的学习 STM32F103系列 FSMC Flexible Static Memory Controller简介 1.详细功能参看《STM32F10x参考手册》,这边是概述 是一个外设,挂载在AHB总线下。 可以用于驱动包括 SRAM、NOR FLASH 以及 NAND FL…...
保姆级教程 --redis启动命令
1、在redis目录 打开命令 windowr 输入cmd 2、输入 redis-server.exe redis.windows.conf 启动redis命令,看是否成功 3、可能会启动失败,报28 Nov 09:30:50.919 # Creating Server TCP listening socket 127.0.0.1:6379: bind: No error 4、报错后&am…...
【C++】构造函数分类 ① ( 构造函数分类简介 | 无参构造函数 | 有参构造函数 | 拷贝构造函数 | 代码示例 - 三种类型构造函数定义与调用 )
文章目录 一、构造函数分类1、构造函数分类简介2、构造函数分类代码分析无参构造函数有参构造函数拷贝构造函数 二、代码示例 - 三种类型构造函数定义与调用 一、构造函数分类 1、构造函数分类简介 C 构造函数可以分为以下几类 : 无参构造函数 : 最简单也是默认的构造函数 , 函…...
胡焕庸线,我国东西地级市分布密度分界线
背景 黑河—腾冲线,又名胡焕庸线,是我国人口密度分布的东西近似分界线。今天把地级市坐标分布密度做成热力图,并与胡焕庸线一起展示时,惊奇的发现,胡焕庸线貌似也是我车东西地级市分布密度的分界线。 生成folium地图…...
里氏替换原则在继承关系中子类对父类方法的重写(覆盖)或重载时应遵循的规则
什么是里氏替换原则:只要父类能出现的地方子类就可以出现,而且 替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。…...
【脑机接口开源数据处理包】brainflowBrainFlow是一个库,旨在获取,解析和分析脑电图,肌电图,心电图和其他类型的数据从生物传感器。
BrainFlow是一个库,旨在获取,解析和分析脑电图,肌电图,心电图和其他类型的数据从生物传感器。 brainflow开源库官网地址 [https://brainflow.readthedocs.io/en/stable/](https://brainflow.readthedocs.io/en/stable/) 它提供了…...
#452. 序列操作
序列操作 - 题目 - Daimayuan Online Judge 问题描述: 思路:首先想的是第二次操作的y可以将前面所以操作进行抵消,只需要第二次操作的最大值即可。但是发现,对于第一个操作,它是单点修改,每修改一次对于第…...
《Python深度学习-Keras》精华笔记3:解决深度学习多分类问题
公众号:机器学习杂货店作者:Peter编辑:Peter 持续更新《Python深度学习》一书的精华内容,仅作为学习笔记分享。 本文是第三篇:介绍如何使用Keras解决Python深度学习中的多分类问题。 多分类问题和二分类问题的区别注意…...
区块链世界的大数据入门之zkMapReduce简介
1. 引言 跨链互操作性的未来将围绕多链dapp之间的动态和数据丰富的关系构建。Lagrange Labs 正在构建粘合剂,以帮助安全地扩展基于零知识证明的互操作性。 2. ZK大数据栈 Lagrange Labs 的ZK大数据栈 为一种专有的证明结构,用于在任意动态分布式计算的…...
Python流程控制语句-条件判断语句练习及应用详解
文章目录 简介条件判断语句(if语句)练习1:判断奇偶数练习2:判断闰年练习3:计算狗的年龄相当于人的年龄练习4:根据成绩奖励练习5:选择婚姻对象 小结 python 学习专栏推荐python基础知识ÿ…...
(十)ElasticSearch高级使用【别名,重建索引,refresh操作,高亮查询,查询建议】
1.别名使用 1)别名作用 在开发中,随着业务需求的迭代,较⽼的业务逻辑就要⾯临更新甚⾄是重构,⽽对于es来说,为了 适应新的业务逻辑,可能就要对原有的索引做⼀些修改,⽐如对某些字段做调整&…...
基于小波神经网络的中药材价格预测,基于ANN的小波神经网络中药材价格预测
目标 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数, BP神经网络的传递函数 小波神经网络(以小波基为传递函数的BP神经网络) 代码链接:基于小波神经网络的中药材价格预测,ANN小波神经网络中药材价格预测资源-CS…...
thinkPhp5返回某些指定字段
//去除掉密码$db new UserModel();$result $db->field(password,true)->where("username{$params[username]} AND password{$params[password]}")->find(); 或者指定要的字段的数组 $db new UserModel();$result $db->field([username,create_time…...
基于docker环境的tomcat开启远程调试
背景: Tomcat部署在docker环境中,使用rancher来进行管理,需要对其进行远程调试。 操作步骤: 1.将容器中的catalina.sh映射出来,便于对其修改,添加远程调试相关参数。 注意:/data/produce2201…...
ELK日志框架图总结
ELK日志框架图总结 本文目录 ELK日志框架图总结Elastic Stack介绍模式分层图beatselasticsearchkibana模式logstashelasticsearchkibana模式beatslogstashelasticsearchkibana模式beats缓存/消息队列logstashelasticsearchkibana模式elkspringboot Elastic Stack介绍 官网&…...
go 每天定时任务 --chatGPT
问:clearLog(hour,cmds),定时执行shell 命令,hour 为每天的几点,cmds 为linux命令数组字符串(如 1,{"ls","cd"}) gpt: 要编写一个 Go 函数 clearLog,该函数可…...
Lightdb 23.3 plorasql函数支持DML
开篇立意 oracle在函数中使用dml语句时,有两者情况。即:(1)直接使用select调用该函数;(2)在匿名块中调用该函数。 针对第一种情况我们测试一下 简单的函数: create table nested_t…...
电容笔值不值得买?开学季比较好用的电容笔
眼看着新学期即将到来,到底应该选择什么样的电容笔?一款原装的苹果Pencil,就卖到了将近一千块,这对于很多人来说,都是一个十分昂贵的价格。事实上,由于平替电容笔的价格非常便宜,只要一二百元就…...
Mybatis 框架 ( 五 ) 分页
4.6.分页 Mybatis-plus 内置分页插件, 并支持多种数据库 官网 : 分页插件 | MyBatis-Plus (baomidou.com) 4.6.1.增加拦截器 通过 MapperScan 指定 mapper接口的路径 import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plug…...
Python模板注入
概念 发生在使用模板引擎解析用户提供的输入时。模板注入漏洞可能导致攻击者能够执行恶意代码或访问未授权的数据。 模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码分离。即也拓宽了攻击面,注入到模板中的代码可…...
wordpress如何设置头像/2023年6月疫情恢复
1、安装VS Code 官网下载安装 2、配置python 安装插件 Python 插件 配置launch.json 配置tasks.json 关于tasks.json配置请参开官方文档 经过以上配置你就可以使用Vs code 来开发Python 程序了!! Vs code 这个开发工具真的是很好用,很多丰富…...
广州网站建设o2o/万网域名查询注册商
信号调制与解调[实验目的]1. 了解用MATLAB 实现信号调制与解调的方法。 2. 了解几种基本的调制方法。 [实验原理]由于从消息变换过来的原始信号具有频率较低的频谱分量,这种信号在许多信道中不适宜传输。因此,在通信系统的发送端通…...
做婚礼设计在哪个网站下载素材/营销策略包括哪些内容
第一次真正意义上的数据技术嘉年华,来自不同方向的原生数据库产品的创造者,架构者,应用者欢聚一堂,分享经验、传播知识、碰撞思维,一起探索数据价值,重塑企业未来! 本届大会更是一次Oracle ACE大…...
ps做的网站保存不了jpg/百度网盘登录首页
源:在 WindowMobile 上的模拟LED 显示屏插件 我在给一个对话框上的控件查找翻看合适的图标时,无形中看到了一个LED显示屏的图标,这里所说的LED显示屏是指由很多LED灯密集排列组成的点阵式LED屏,比如在股市交易所,公交车…...
北京做网站那家好/新闻最近的新闻
作者:Jamie Hannaford翻译:bbbmj(才云)校对:bot(才云)源代码解释版(强烈建议阅读):https://github.com/bbbmj/what-happens-when-k8s想象一下,当你…...
石家庄微网站建设公司/湖北seo服务
什么是Node.js Node是一个服务器端JavaScript解释器。Node的目标是帮助程序员构建高度可伸缩的应用程序,编写能够处理数万条同时连接到一个物理机的连接代码。处理高并发和异步I/O是Node受到开发人员的关注的原因之一。 Node本身运行Google V8 JavaScript引擎&…...