Linux —— Socket编程(三)
一、本章重点
1. tcp服务器实现思路,进一步了解和总结相关的接口
2. 了解日志和守护进程
二、tcp服务器核心思路
tcp版的服务器与udp的不同在于,udp是面向数据报传输数据,在数据传输中不需要建立与客户端的链接,直接用recvfrom和sendto这两个接口进行消息的收发,而tcp版的服务器则是面向字节流的,需要与客户端建立连接
1. 创建监听套接字listen_sock
这个监听套接字是用于监听的,监听就可以看做为等待客户端连接,监听套接字只负责与客户端建立起连接,然后剩下的任务交给其他的套接字去执行
// 1. 创建ListenSock_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){std::cerr << "create socket error" << std::endl;exit(SOCKET_ERR);}
2. 创建好struct sockaddr_in ,并将其与套接字bind
这里和udp是一样的步骤
// 2. bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_addr.s_addr = htonl(INADDR_ANY);local.sin_family = AF_INET;local.sin_port = htons(_port);if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0){std::cerr << "bind error" << std::endl;exit(BIND_ERR);}
3. 监听 -- listen
//?
if (listen(_listensock, backlog) < 0){std::cerr << "listen socket error" << std::endl;exit(LISTEN_ERR);}
4. 获取连接 -- accept
获取连接其实就是获取客户端的连接,它会返回一个套接字,后续的业务处理则是根据这个套接字去实现和完成的
// 1. 获取连接 -- accept
struct sockaddr_in client;
socklen_t len = sizeof(client);
int sock = accept(_listensock, (struct sockaddr *)&client, &len);
if (sock < 0)
{std::cerr << "sock error" << std::endl;exit(SOCKET_ERR);
}
5. 开展业务处理.
具体开展的业务处理要采用多进程或者多线程的方式,主线程负责监听连接,而其他线程负责为客户端提供具体服务。tcp的读写可以直接使用以往的文件相关的读写函数,如read、write等等
// 3. 开展业务处理 -- service// 测试std::cout << "连接成功:" << sock << " from " << _listensock << "," << client_ip << " - " << client_port << std::endl;// service(sock,client_ip,client_port);// 业务处理需要和监听同时进行,因为这里的业务处理是阻塞等待客户端的// 3.1 多进程方案 -- 如何处理进程等待的阻塞问题?// pid_t id = fork();// if (id < 0)// {// close(sock);// continue;// ;// }// else if (id == 0) // child// {// close(_listensock);// service(sock, client_ip, client_port);// exit(0);// }// close(sock); -- 线程方案中不能关闭这个// 进程等待 -- waitpid// 方案一:信号忽略 -- signal(SIGCHLD, SIG_IGN);(推荐)// 方案二:信号捕捉 -- signal(SIGCHLD, handler);(麻烦,不太推荐)// 方案三:轮询等待 -- WNOHANG(不太推荐)// 方案四:孤儿进程 -- if(fork() > 0) exit(0);(不太推荐,但思路很优秀,但是会对系统有负担)// pid_t ret = waitpid(id, nullptr, 0);// if (ret == id)// std::cout << "wait child: " << id << " success" << std::endl;// 3.2 多线程方案 -- 线程池优化// pthread_t tid;// ThreadData* td = new ThreadData(sock,client_ip,client_port,this);// pthread_create(&tid,nullptr,threadRoutine,td);Task t(sock, client_ip, client_port, std::bind(&TcpServer::service, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));//?ThreadPool<Task>::getinstance()->pushTask(t);
三、Socket编程相关接口整理
1. 网络编程相关的头文件
#include<sys/types.h> // 包含很多系统数据类型
#include<sys/socket.h> // 包含了基本的 socket 函数和数据结构定义。
#include<netinet/in.h> // 定义了 Internet 地址族相关的结构和函数。
#include<arpa/inet.h> // 提供 IP 地址转换函数。
2. socket -- 创建套接字函数
int socket(int domain, int type, int protocol);
domain:指定通信域,常见的有AF_INET(IPv4网络协议)和AF_INET6(IP6网络协议)。
type:指定套接字类型,常见的有SOCK_STREAM(面向字节流,对应TCP)和SOCK_DGRAM(面向数据报,对应UDP)
protocol:通常设置为0,表示使用默认协议。
返回值: 一般是文件文件描述符fd,若失败则返回小于0的值
3. struct sockaddr_in
sin_family:第一行的宏转换后就是这个,它指定的是地址族,对于IPv4就设置为AF_INET
sin_port:端口号,要以网络字节序去表示,所以这里一般在填写的时候,还要配合网络字节序的接口htons
sin_addr:里面封装的内容实际就是IP地址,可以使用inet_addr 或 inet_pton函数将点分十进制的 IP 地址字符串转换为合适的格式并存储在
sin_addr.s_addr
中。当然这里由于我们用的是云服务器,前面提到云服务器的IP地址不能填唯一确定的,而是这里需要填INADDR_ANY
4. bind 绑定套接字和struct sockaddr的函数接口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd : 是通过socket函数创建的套接字描述符。
addr:该结构体的解释在知识点三和知识点四有讲解,对于 IPv4 通常是
struct sockaddr_in
类型,对于 IPv6 是struct sockaddr_in6
类型。这个地址结构包含了要绑定的 IP 地址和端口号等信息。addrlen:结构体的大小
返回值说明:成功返回0,失败返回-1,并将错误码进行设置
5. recvfrom -- 从套接字中获取信息
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
sockfd:套接字描述符
buf:接受数据的数据缓冲区指针,用于接受数据的
len:数据缓冲区的大小
flags:一般设置为0,表示默认的接收行为,也可以设置一些标志位来影响接收操作的行为,例如
MSG_PEEK
(查看数据但不实际读取,数据仍留在接收队列中)、MSG_WAITALL
(尽可能等待接收完整的请求数据量)等,但这些标志位的使用相对较少from:是一个struct sockaddr*类型的结构体指针,它用来获取发送方的地址信息
fromlen:是一个指向整数的指针,用于指定
from
所指向的地址结构的长度。在调用recvfrom
之前,应该将*fromlen
设置为sizeof(struct sockaddr)
(或对应的具体地址结构的大小);当recvfrom
返回时,fromlen
会被修改为实际存储在from
中的地址结构的长度返回值说明:成功返回收到的字节数,返回值为0说明对端已经关闭了连接,返回-1表示接受数据发生了错误
6. sendto -- 向套接字中写入信息
int sendto(int sockfd, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
sockfd:是通过socket函数创建的套接字描述符
buf:要向套接字发送的数据所在的缓冲区指针
len:指定要发生内容的长度
flags: 一般设置为 0,表示默认的发送行为。也可以设置一些标志位来影响发送操作的行为,不过这些标志位的使用相对较少
to:要发送到的目的地的struct sockadd的指针
tolen:to的大小
7. 网络字节序接口
#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);//将源主机中32位长整形转换成网络字节序要求的大端格式
uint16_t htons(uint16_t hostshort);//将源主机中16位短整形转换成网络字节序要求的大端格式
uint32_t ntohl(uint32_t netlong);//将网络中32位长整形(大端)转换成当前主机的格式
uint16_t ntohs(uint16_t netshort);//将网络中16位短整形(大端)转换成当前主机的格式
8. listen 监听
int listen(int sockfd, int backlog);
它用于将一个套接字标记为被动套接字,也就是将其设置为用于监听连接请求的状态。这个套接字通常是由socket
函数创建并经过bind
函数绑定到一个本地地址和端口之后使用。
sockfd
:是由socket
函数创建并经过bind
绑定后的套接字描述符。backlog
:指定了在拒绝连接之前,操作系统可以暂存的未完成连接请求的最大数量。它实际上定义了连接请求队列的长度。当有多个客户端同时尝试连接服务器时,这些连接请求会被放入这个队列中等待服务器处理。如果队列已满,新的连接请求可能会被拒绝(具体行为可能因操作系统而异)。- 返回值:如果
listen
函数调用成功,则返回 0;如果失败,则返回 -1,并设置相应的错误代码,可以通过perror
等函数查看错误信息
9. accept 连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
它用于从处于监听状态的套接字的连接请求队列中取出一个连接请求,并创建一个新的套接字来与客户端进行通信。这个新的套接字与原来监听的套接字不同,它是专门用于和客户端进行数据交互的。
sockfd
:仍然是最初由socket
函数创建并经过bind
和listen
操作的监听套接字描述符。addr
:是一个指向sockaddr
结构体的指针,用于存储客户端的地址信息。如果不需要获取客户端地址信息,可以将其设置为NULL
。addrlen
:是一个指向socklen_t
类型变量的指针,它用于在函数调用前传入addr
所指向的结构体的长度,在函数返回时,它会被设置为实际存储客户端地址信息所占用的长度。- 返回值:如果
accept
函数调用成功,则返回一个新的套接字描述符,这个描述符用于与客户端进行后续的通信;如果失败,则返回 -1,并设置相应的错误代码,可以通过perror
等函数查看错误信息。
四、日志
往往在项目工程中,我们会有需要不同的调试信息,以及可能一些需要标记或者记录的信息,例如用户连接成功的信息,用户的消息记录等等,这些我们之前都是直接打印在屏幕上的,但实际在工程项目中,我们都需要将这些信息打印到文件中进行管理,这里我们简单实现一下应该粗糙的日志。
1. 可变参数
在写日志代码前,还需要对可变参数有一些了解,像C语言中的printf的实现就是用可变参数的方式实现,那么我们要如何使用呢?
#include <cstdarg> // 头文件
void func(const char *format,...) // 可变参数前,至少要有一个确定的参数format
va_list p; // p变量本质是一个char*的指针
va_start(p, format); // p指向可变参数部分的起始地址
int a = va_arg(p, int); // 根据类型提取参数
va_end(p); // p = NULL;
以上是对于可变参数的预备知识,我们要用可变参数的是为了让打印日志信息函数中,可以让外部传入的日志信息可以是多样的,像printf一样使用,所以可以用到一个函数帮助我们
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
str是数据缓冲区
size是缓冲区大小
format是一个格式化字符串,用于指定输出的格式,其格式规则与
printf
函数中的格式化字符串类似,包含普通字符和格式转换说明符(如%d
、%f
、%s
等)ap是一个
va_list
类型的变量,用于传递可变参数列表。它通常是由va_start
宏初始化后得到的
2. 参考代码
#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>// 日志是有日志等级的const std::string filename = "log/tcpserver.log";enum
{Debug = 0,Info,Warning,Error,Fatal,Uknown
};static std::string toLevelString(int level)
{switch (level){case Debug:return "Debug";case Info:return "Info";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "Uknown";}
}static std::string getTime()
{time_t curr = time(nullptr);struct tm *tmp = localtime(&curr);char buffer[128];snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d", tmp->tm_year + 1900, tmp->tm_mon+1, tmp->tm_mday,tmp->tm_hour, tmp->tm_min, tmp->tm_sec);return buffer;
}// 日志格式: 日志等级 时间 pid 消息体
// logMessage(DEBUG, "hello: %d, %s", 12, s.c_str()); // DEBUG hello:12, world
void logMessage(int level, const char *format, ...)
{char logLeft[1024];std::string level_string = toLevelString(level);std::string curr_time = getTime();snprintf(logLeft, sizeof(logLeft), "[%s] [%s] [%d] ", level_string.c_str(), curr_time.c_str(), getpid());char logRight[1024];va_list p;va_start(p, format);vsnprintf(logRight, sizeof(logRight), format, p);va_end(p);// 打印// printf("%s%s\n", logLeft, logRight);// 保存到文件中FILE *fp = fopen(filename.c_str(), "a");if(fp == nullptr)return;fprintf(fp,"%s%s\n", logLeft, logRight);fflush(fp); //可写也可以不写fclose(fp);// 预备// va_list p; // char *// int a = va_arg(p, int); // 根据类型提取参数// va_start(p, format); //p指向可变参数部分的起始地址// va_end(p); // p = NULL;
}
五、守护进程
1. 概念
要理解守护进程,我们先需要知道一些关于Liunx系统的概念。
首先要理解关于进程、进程组、会话,这三个概念
- 进程是基础
进程是计算机系统中正在运行的程序的实例,是操作系统进行资源分配和调度的基本单位。它拥有自己独立的内存空间和系统资源,有自己的生命周期。- 进程组是相关进程的集合
进程组由一个共同的祖先进程创建的多个相关进程组成。这些进程在某些行为上具有一致性,比如共享一个进程组 ID,对某些信号的处理方式相同。一个进程可以属于一个进程组。- 会话是包含多个进程组的逻辑概念
会话通常与一个控制终端相关联,当用户登录系统时创建。一个会话可以包含多个不同类型的进程组,这些进程组中的进程对于某些信号的处理方式是相关的。会话支持作业控制操作。- 总体关系
一个进程可以属于一个进程组,一个进程组可以属于一个会话。从范围上看,会话包含多个进程组,进程组包含多个相关进程。
我们现在使用的Xshell去登录远端的Linux服务器,每次登录其实是在整个Linux系统上启动了一个会话,而bash进程作为首个登入的进程,同时也是对应进程组的组长
而守护进程就是,我们要将原先我们在该会话中写的进程,将其独立出去作为一个单独的会话层面的进程,让它在后台运行,一般的服务器都是如此,这样就不会因为我们会话关闭而服务器挂掉。
守护进程要实现还有几个条件:
- 与控制终端脱离
- 守护进程需要与任何控制终端脱离关系。这是因为如果守护进程依赖于控制终端,当终端关闭时(例如用户退出登录),守护进程可能会收到一些信号(如 SIGHUP)导致其异常终止。通常通过调用
setsid
函数来创建一个新的会话,使守护进程成为新会话的首进程,从而脱离原来的控制终端。- 改变工作目录
- 守护进程一般会改变其工作目录到根目录(
/
)或者其他合适的目录。这是为了避免因为工作目录所在的文件系统被卸载等原因导致守护进程出现问题。例如,如果守护进程的工作目录在一个用户可卸载的文件系统上,当该文件系统被卸载时,守护进程可能无法正常访问其工作目录中的文件。- 重设文件描述符
- 守护进程需要关闭所有不需要的文件描述符。在进程创建时,会继承父进程的一些文件描述符,如果不关闭这些不必要的文件描述符,可能会导致资源浪费以及潜在的问题。例如,守护进程可能会因为某个打开的文件描述符指向一个已经不存在的文件(如终端相关的文件描述符)而出现错误。通常会关闭标准输入、标准输出和标准辅助输入输出等文件描述符(0、1、2),并可以根据需要重新打开一些文件描述符用于日志记录等用途。
- 设置合适的文件权限掩码
- 守护进程通常会设置合适的文件权限掩码(
umask
)。文件权限掩码决定了新创建文件的默认权限。通过设置合适的文件权限掩码,可以确保守护进程创建的文件具有合适的权限,避免出现安全问题或文件无法正常使用的情况。- 忽略某些信号
- 守护进程需要忽略一些信号,比如 SIGHUP 信号。因为守护进程已经与控制终端脱离,如果不忽略 SIGHUP 信号,当终端关闭时,守护进程可能会收到该信号并错误地终止。同时,守护进程也可能需要忽略其他一些不相关的信号,以确保其稳定运行。
2. 参考代码
#pragma once
// 1. setsid();
// 2. setsid(), 调用进程,不能是组长!我们怎么保证自己不是组长呢?
// 3. 守护进程a. 忽略异常信号 b. 0,1,2要做特殊处理 c. 进程的工作路径可能要更改 /#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include "log.hpp"
#include "err.hpp"//守护进程的本质:是孤儿进程的一种!
void Daemon()
{// 1. 忽略信号signal(SIGPIPE, SIG_IGN);signal(SIGCHLD, SIG_IGN);// 2. 让自己不要成为组长if (fork() > 0)exit(0);// 3. 新建会话,自己成为会话的话首进程pid_t ret = setsid();if ((int)ret == -1){logMessage(Fatal, "deamon error, code: %d, string: %s", errno, strerror(errno));exit(SETSID_ERR);}// 4. 可选:可以更改守护进程的工作路径// chdir("/")// 5. 处理后续的对于0,1,2的问题int fd = open("/dev/null", O_RDWR);if (fd < 0){logMessage(Fatal, "open error, code: %d, string: %s", errno, strerror(errno));exit(OPEN_ERR);}dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);
}
总结
本篇文章主要是整理了Socket编程常见的接口,还有对tcp服务器相关的概念知识点
相关文章:
Linux —— Socket编程(三)
一、本章重点 1. tcp服务器实现思路,进一步了解和总结相关的接口 2. 了解日志和守护进程 二、tcp服务器核心思路 tcp版的服务器与udp的不同在于,udp是面向数据报传输数据,在数据传输中不需要建立与客户端的链接,直接用recvfrom…...
5G N2 N3 N6 NB口
在5G架构中,N2、N3和N6是三种关键的接口,每个接口都有其特定的功能和应用场景。 N2接口: N2接口是5G无线接入网(RAN)与5G核心网(5GC)之间的控制面接口。它主要负责传递控制平面消息,…...
【数据结构】堆(Heap)详解
在深入了解堆这一重要的数据结构之前,不妨先回顾一下我之前的作品 ——“二叉树详解”。 上篇文章👉剖析二叉树(Binary Tree) 二叉树作为一种基础的数据结构,为我们理解堆以及其他更复杂的数据结构奠定了坚实的基础。它…...
《Linux从小白到高手》理论篇(四):Linux用户和组相关的命令
List item 本篇介绍Linux用户和组相关的命令,看完本文,有关Linux用户和组相关的常用命令你就掌握了99%了。Linux用户和组相关的命令可以分为以下六类: 一.用户和用户组相关查询操作命令: Id id命令用于显示用户的身份标识。常见…...
OpenGL ES 之EGL(6)
OpenGL ES 之EGL(6) 简述 EGL是OpenGL ES的封装,目的是跨设备跨平台,隔离不同平台对窗口不同的实现。上一节我们基本没有使用到EGL,因为GLSurfaceView帮助我们处理了相关的逻辑,我们这一节来看一下EGL的一些概念以及接口的使用。…...
kotlin 委托
一、类委托 interface DB{fun insert() } class SqliteDB : DB {override fun insert() {println(" SqliteDB insert")} }class MySql : DB{override fun insert() {println(" MySql insert")} }class OracleDB : DB{override fun insert() {println(&quo…...
Stream流的中间方法
一.Stream流的中间方法 注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程 注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据 二.filter filter的主要用法是…...
【车载开发系列】ParaSoft单元测试环境配置(四)
【车载开发系列】ParaSoft单元测试环境配置(四) 【车载开发系列】ParaSoft单元测试环境配置(四) 【车载开发系列】ParaSoft单元测试环境配置(四)一. 如何设置过滤二. 如何设置静态扫描的规则三. 如何设置单…...
IDEA 设置自动定位文件
一、场景分析 IDEA 在使用的过程中,发现有时候,打开一个类,它并不能自动帮我们在左侧 Project 树中定位出文件,需要自己手动点击 瞄准 图标。很不方便。 二、解决方法 1、点击 瞄准 图标旁边的 竖三点 2、将 Alwasy Select Opene…...
Nature Machine Intelligence 基于强化学习的扑翼无人机机翼应变飞行控制
尽管无人机技术发展迅速,但复制生物飞行的动态控制和风力感应能力,仍然遥不可及。生物学研究表明,昆虫翅膀上有机械感受器,即钟形感受器campaniform sensilla,探测飞行敏捷性至关重要的复杂气动载荷。 近日࿰…...
[Web安全 网络安全]-XXE 外部实体注入攻击XML
文章目录: 一:前言 1.定义 1.1 XXE 1.2 XML可扩展标记语言 2.DDT文档类型定义 2.1 分类 2.2 元素element DTD元素 DTD属性 2.3 实体entity DTD实体类别 DTD实体声明引用 声明:内部 外部 参数实体 公共实体 引用:…...
8--苍穹外卖-SpringBoot项目中套餐管理 详解(二)
目录 删除套餐 需求分析和设计 代码开发 根据id查询套餐 mapper层 Service层 ServiceImpl层 Mapper层 批量删除套餐 mapper层 Service层 ServiceImpl层 Mapper层 SetmealMapper.xml 修改套餐 需求分析和设计 代码开发 起售停售套餐 需求分析和设计 代码开发…...
测试面试题:pytest断言时,数据是符点类型,如何断言?
在使用 Pytest 进行断言时,如果数据是浮点类型,可以使用以下方法进行断言: 一、使用pytest.approx pytest.approx可以用来比较两个浮点数是否近似相等。例如: import pytestdef test_float_assertion():result 3.14159expecte…...
Python与MongoDB交互
一、基本概念 MongoDB: 一个面向文档的数据库系统,使用BSON(Binary JSON)作为存储格式。集合(Collection): 类似于关系型数据库中的表,是文档的集合。文档(Document): MongoDB中的基…...
安卓AI虚拟女友项目开发的Android开发环境搭建
第五章:Android开发环境搭建与基础入门 5-1 项目讲解思路说明 本文是安卓AI数字虚拟人项目实战的第五章,开发安卓AI安卓版数字虚拟人的Android基础部分。 在本章中,我们将详细介绍如何搭建Android开发环境,包括Android Studio的…...
基于SpringBoot+Vue+MySQL的智能垃圾分类系统
系统展示 用户前台界面 管理员后台界面 系统背景 随着城市化进程的加速,垃圾问题日益凸显,不仅对环境造成污染,也给城市管理带来了巨大挑战。传统的垃圾分类方式不仅费时费力,而且手工操作容易出现错误,导致垃圾分类效…...
你的个人文件管理助手:AI驱动的本地文件整理工具
🌐 引言 在数字化时代,我们经常面临文件管理的挑战。电脑中的文件杂乱无章,寻找特定文件变得既费时又费力。幸运的是,现在有了一款名为本地文件整理器的神器,它利用AI技术帮助你快速、智能地整理文件,同时…...
【PyTorch】环境配置
框架介绍 Pytorch简介 2017年1月,FAIR(Facebook AI Research)发布了PyTorch。PyTorch是在Torch基础上用python语言重新打造的一款深度学习框架。Torch是采用Lua语言作为接口的机器学习框架,但因为Lua语言较为小众,导…...
枫叶MTS格式转换器- 强大、操作简单的MTS、M2TS视频转换工具供大家学习研究参考
一款功能强大、操作简单的MTS、M2TS视频转换工具,欢迎下载使用。 使用本MTS格式转换器可以帮助您将索尼和松下等摄像机录制的MTS、M2TS格式高清视频转换为其他流行的视频格式,如MP4、3GP、AVI、MPEG、WMV、ASF、MOV、RM、VCD、SVCD、DVD、MKV、FLV、SWF、MPG、MP3、WAV、WMA…...
Vscode把全部‘def‘都收起来的快捷键
在 VSCode 中,你可以使用以下快捷键来收起所有函数定义 (def): Windows/Linux: Ctrl K, Ctrl 0macOS: Cmd K, Cmd 0 这个快捷键组合会折叠当前文件中所有的代码块(包括所有函数和类定义)。你可以通过相同的快捷键再次展开这…...
Web和UE5像素流送、通信教程
一、web端配置 首先打开Github地址:https://github.com/EpicGamesExt/PixelStreamingInfrastructure 找到自己虚幻引擎对应版本的项目并下载下来,我这里用的是5.3。 打开项目找到PixelStreamingInfrastructure-master > Frontend > implementat…...
【YOLO目标检测电梯间电动车与人数据集】共4321张、已标注txt格式、有训练好的yolov5的模型
目录 说明图片示例 说明 数据集格式:YOLO格式 图片数量:4321 标注数量(txt文件个数):4321 标注类别数:2 标注类别名称:person、electricBicycle 数据集下载:电梯间电动车与人数据集 图片示例 数据…...
【网络安全】公钥基础设施
1. PKI 定义 1.1 公钥基础设施的概念 公钥基础设施(Public Key Infrastructure,简称PKI)是一种基于公钥密码学的系统,它提供了一套完整的解决方案,用于管理和保护通过互联网传输的信息。PKI的核心功能包括密钥管理、…...
云原生(四十一)| 阿里云ECS服务器介绍
文章目录 阿里云ECS服务器介绍 一、云计算概述 二、什么是公有云 三、公有云优缺点 1、优点 2、缺点 四、公有云品牌 五、市场占有率 六、阿里云ECS概述 七、阿里云ECS特点 阿里云ECS服务器介绍 一、云计算概述 云计算是一种按使用量付费的模式,这种模式…...
计算机网络:计算机网络体系结构 —— OSI 模型 与 TCP/IP 模型
文章目录 计算机网络体系结构OSI 参考模型TCP/IP 参考模型分层的必要性物理层的主要问题数据链路层的主要问题网络层的主要问题运输层的主要问题应用层的主要问题 分层思想的处理方法发送请求路由器转发接受请求发送响应接收响应 计算机网络体系结构 计算机网络体系结构是指将…...
【openwrt-21.02】T750 openwrt switch划分VLAN之后网口插拔状态异常问题分析及解决方案
Openwrt版本 NAME="OpenWrt" VERSION="21.02-SNAPSHOT" ID="openwrt" ID_LIKE="lede openwrt" PRETTY_NAME="OpenWrt 21.02-SNAPSHOT" VERSION_ID="21.02-snapshot" HOME_URL="https://openwrt.org/" …...
C++随心记
C随心记 C中的 CONST C中的const是表示不可修改 int main() {/* 对于变量而言 */// 不可修改的常量const int A 10;// 不可修改的指针指向const int* pointer_0 nullptr;int const* poniter_1 nullptr;// 不可修改指针指向的内容int* const poniter_2 nullptr; }const也…...
【微服务即时通讯系统】——brpc远程过程调用、百度开源的RPC框架、brpc的介绍、brpc的安装、brpc使用和功能测试
文章目录 brpc1. brpc的介绍1.1 rpc的介绍1.2 rpc的原理1.3 grpc和brpc 2. brpc的安装3. brpc使用3.1 brpc接口介绍 4. brpc使用测试4.1 brpc同步和异步调用 brpc 1. brpc的介绍 1.1 rpc的介绍 RPC(Remote Procedure Call)远程过程调用,是一…...
鸿蒙开发(NEXT/API 12)【状态查询与订阅】手机侧应用开发
注意 该接口的调用需要在开发者联盟申请设备基础信息权限与穿戴用户状态权限,穿戴用户状态权限还需获得用户授权。 实时查询穿戴设备可用空间、电量状态。订阅穿戴设备连接状态、低电量告警、用户心率告警。查询和订阅穿戴设备充电状态、佩戴状态、设备模式。 使…...
vite中sass警告JS API过期
1.问题 在Vite创建项目中引入Sass弹出The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 - vite中sass警告JS API过期 The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0警告提示表明你当前正在使用的 Dart Sass 版本中&#…...
邯郸建设网站/潍坊seo关键词排名
wip限制进行中的工作限制(从现在开始是WIP限制)是我在工作中遇到的最强大但违反直觉的概念之一。 当建议团队在董事会中引入WIP限制时,我听到“例如,您是说同时做更少的事情会提高您的速度吗? 你一定错了吗࿱…...
微信小程序商店wordpress做/网站制作论文
10月28日,据外媒 the Register 报道,LG 的 Hom-bot 系列智能机器人吸尘器被曝有新安全漏洞“HomeHack” ,利用该漏洞,攻击者可以控制 Hom-bot 系列智能机器人吸尘器,获得行动和控制权以及对机器人内置摄像机镜头的访问…...
做城市门户网站怎么发展/个人发布信息免费推广平台
介绍Python代码审计方法多种多样,但是总而言之是根据前人思路的迁移融合扩展而形成。目前Python代码审计思路,呈现分散和多样的趋势。Python微薄研发经验以及结合实际遇到的思路和技巧进行总结,以便于朋友们的学习和参考。SQL注入和ORM注入这…...
网站建设哪里好/优化公司网站排名
最近,TP公司刚推出了新款的云台变焦无线室内摄像机TL-IPC43ANZ,无论家庭还是店铺监控,除了需要大的视场角看清全局,也经常要看人脸、收银台、宠物等细节。普通定焦摄像机很难兼顾这两点,针对这样的使用场景,…...
wordpress导出数据库/整站优化代理
2007-11-11 21:26select系统调用是用来让我们的程序监视多个文件句柄(file descriptor)的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变。文件在句柄在Linux里很多,如果你man某个函数,在函数返回值…...
织梦教育培训网站源码/杭州搜索引擎排名
SQL的组成部分 DML Data Manipulation Language数据的增删改DDL Data Definition language库或表的增删改DCL Data Control Language用户的创建、授权TCL Transaction Control Language事务控制(Oracle)DQL Data Query Language数据查询(MyS…...