【阿里云】图像识别 智能分类识别 增加网络控制功能点(三)

一、增加网络控制功能

  • 实现需求
  • TCP 心跳机制解决Soket异常断开问题

二、Linux内核提供了通过sysctl命令查看和配置TCP KeepAlive参数的方法。

  • 查看当前系统的TCP KeepAlive参数
  • 修改TCP KeepAlive参数

三、C语言实现TCP KeepAlive功能
四、setsockopt用于设置套接字选项的系统调用
五、代码实现
六、待定

一、增加网络控制功能

Linux网络编程(TCP Socket编程实现过程)
TCP Keepalive HOWTO

实现需求:

Socket网络编程,通过Socket远程接入控制垃圾识别功能。

TCP 心跳机制解决Soket异常断开问题

Socket客户端得断开情形无非就两种情况:

  1. 客户端能够发送状态给服务器;正常断开,强制关闭客户端等,客户端能够做出反应。
  2. 客户端不能发送状态给服务器;突然断网,断电,客户端卡死等,客户端根本没机会做出反应,服务器更不了解客户端状态,导致服务器异常等待。

为了解决上述问题,引入TCP心跳包机制:
心跳包的实现,心跳包就是服务器定时向客户端发送查询信息,如果客户端有回应就代表连接正常,类似于linux系统的看门狗机制。心跳包的机制有一种方法就是采用TCP_KEEPALIVE机制,它是一种用于检测TCP连接是否存活的机制,它的原理是在一定时间内没有数据往来时,发送探测包给对方,如果对方没有响应,就认为连接已经断开。TCP_KEEPALIVE机制可以通过设置一些参数来调整,如探测时间间隔、探测次数等。

二、Linux内核提供了通过sysctl命令查看和配置TCP KeepAlive参数的方法。

在 Linux 内核中,可以通过 sysctl 命令来查看和配置 TCP KeepAlive 参数。TCP KeepAlive 是一种机制,用于在两个端点之间的连接空闲时检测连接的活跃性。

以下是一些与 TCP KeepAlive 相关的 sysctl 参数以及它们的含义:

  1. tcp_keepalive_time:
    • 含义:TCP KeepAlive 的开始时间。表示连接空闲的时间,超过这个时间,内核开始发送 KeepAlive 消息。
    • 默认值:7200 秒(2 小时)
sysctl net.ipv4.tcp_keepalive_time
  1. tcp_keepalive_intvl:
    • 含义:两次 KeepAlive 消息之间的时间间隔。
    • 默认值:75 秒
sysctl net.ipv4.tcp_keepalive_intvl
  1. tcp_keepalive_probes:
    • 含义:在放弃连接之前发送的 KeepAlive 消息的次数。
    • 默认值:9 次
sysctl net.ipv4.tcp_keepalive_probes

这些参数的配置可以通过修改 /etc/sysctl.conf 文件来实现。例如,要将 tcp_keepalive_time 设置为 600 秒,可以在 /etc/sysctl.conf 中添加如下行:

net.ipv4.tcp_keepalive_time = 600

然后,可以运行以下命令使更改生效:

sysctl -p

请注意,修改这些参数可能会对系统的整体性能产生影响,因此在进行更改之前,请仔细了解每个参数的含义以及它们的默认值。

查看当前系统的TCP KeepAlive参数

sysctl net.ipv4.tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_probes
sysctl net.ipv4.tcp_keepalive_intvl

修改TCP KeepAlive参数

sysctl net.ipv4.tcp_keepalive_time=3600

在这里插入图片描述
在这里插入图片描述

三、C语言实现TCP KeepAlive功能

对于Socket而言,可以在程序中通过socket选项开启TCP KeepAlive功能,并配置参数。

对应的Socket选项分别为 SO_KEEPALIVE 、TCP_KEEPIDLE 、 TCP_KEEPCNT 、 TCP_KEEPINTVL 。

关于 setsockopt 函数的参数和相应的套接字选项以及协议的对应关系,以及对应的描述。

setsockopt 参数描述对应的 Socket Level(SOL)对应的协议(Protocol)
SO_KEEPALIVE启用或禁用在套接字上发送保持活动消息。保持活动消息用于检测连接是否仍然活动。SOL_SOCKETIPPROTO_TCP
TCP_KEEPIDLE指定连接在 TCP 开始发送保持活动探测之前必须空闲的时间(以秒为单位)。SOL_TCPIPPROTO_TCP
TCP_KEEPCNT指定在将连接视为中断之前 TCP 应发送的最大保持活动探测次数。SOL_TCPIPPROTO_TCP
TCP_KEEPINTVL指定个别保持活动探测之间的时间(以秒为单位)。SOL_TCPIPPROTO_TCP
IPPROTO_TCPTCP(传输控制协议)的协议级别。用于设置特定于 TCP 的套接字选项。N/AIPPROTO_TCP

setsockopt 中参数与套接字选项和协议的关系。

Socket 选项和 TCP 参数

选项/参数描述
SO_KEEPALIVE启用或禁用在套接字上发送保持活动消息。保持活动消息用于检测连接是否仍然活动。
TCP_KEEPIDLE指定连接在 TCP 开始发送保持活动探测之前必须空闲的时间(以秒为单位)。
TCP_KEEPCNT指定在将连接视为中断之前 TCP 应发送的最大保持活动探测次数。
TCP_KEEPINTVL指定个别保持活动探测之间的时间(以秒为单位)。
# 四、setsockopt用于设置套接字选项的系统调用

setsockopt 函数是用于设置套接字选项的系统调用。下面是 setsockopt 函数的基本格式:

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

其中:

  • sockfd:套接字文件描述符。
  • level:选项所在的协议层。常用的有 SOL_SOCKET(用于通用套接字选项)和特定的协议层如 IPPROTO_TCP(用于 TCP 协议选项)。
  • optname:选项名称,用于指定需要设置的具体选项。
  • optval:指向包含选项值的缓冲区的指针。
  • optlen:指定 optval 缓冲区的大小。

下面是一些常见的套接字选项和它们的作用:

  1. SO_KEEPALIVE(SOL_SOCKET)

    • 描述:启用或禁用在套接字上发送保持活动消息。保持活动消息用于检测连接是否仍然活动。
  2. TCP_KEEPIDLE(SOL_TCP)

    • 描述:指定连接在 TCP 开始发送保持活动探测之前必须空闲的时间(以秒为单位)。
  3. TCP_KEEPCNT(SOL_TCP)

    • 描述:指定在将连接视为中断之前 TCP 应发送的最大保持活动探测次数。
  4. TCP_KEEPINTVL(SOL_TCP)

    • 描述:指定个别保持活动探测之间的时间(以秒为单位)。
  5. IPPROTO_TCP

    • 描述:TCP(传输控制协议)的协议级别。用于设置特定于 TCP 的套接字选项。

这些选项可用于控制套接字的行为,如保持连接活动、调整发送和接收缓冲区的大小等。在使用时,请注意确保提供正确的协议级别和选项名称。

int keepalive = 1; // 开启TCP KeepAlive功能
int keepidle = 5; // tcp_keepalive_time 3s内没收到数据开始发送心跳包
int keepcnt = 3; // tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒
int keepintvl = 3; // tcp_keepalive_intvl 每3s发送一次心跳包setsockopt(client_socketfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));
setsockopt(client_socketfd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(keepidle));
setsockopt(client_socketfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof(keepcnt));
setsockopt(client_socketfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(keepintvl));

五、代码实现

mysocket.h

#ifndef __MYSOCKET__H
#define __MYSOCKET__H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <unistd.h>#define IPADDR "192.168.1.254" //填写自己实际的ip地址
#define IPPORT "8192"
#define BUF_SIZE 6int socket_init(const char *ipaddr, const char *port);#endif

mysocket.c

#include "mysocket.h"int socket_init(const char *ipaddr, const char *port)
{int server_fd = -1;struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(struct sockaddr_in));// 创建服务器套接字server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == -1) {perror("Socket creation failed");return -1;}// 设置服务器地址结构server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);
//  server_addr.sin_addr.s_addr = INADDR_ANY;inet_aton(ipaddr, &server_addr.sin_addr);// 绑定服务器套接字if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Binding failed");return -1;}// 监听传入的连接请求if (listen(server_fd, 1) == 0) {	//只监听1个连接,排队扔垃圾printf("Listening for incoming connections...\n");} else {perror("Listening failed");return -1;}return server_fd;
}

main.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <wiringPi.h>
#include <pthread.h>#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"
#include "mysocket.h"int serial_fd = -1; // 串口文件描述符
pthread_cond_t cond; // 条件变量,用于线程之间的条件同步
pthread_mutex_t mutex; // 互斥锁,用于线程之间的互斥访问// 判断进程是否在运行
static int detect_process(const char * process_name)
{int n = -1; // 存储进程PID,默认为-1FILE *strm;char buf[128] = {0}; // 缓冲区// 构造命令字符串,通过ps命令查找进程sprintf(buf, "ps -ax | grep %s|grep -v grep", process_name);// 使用popen执行命令并读取输出if ((strm = popen(buf, "r")) != NULL) {if (fgets(buf, sizeof(buf), strm) != NULL) {printf("buf = %s\n", buf); 	//打印缓存区的内容n = atoi(buf); 				// 将进程ID字符串转换为整数printf("n = %d\n", n); 		// 打印下进程的PID}}else {return -1; // popen失败}	pclose(strm); // 关闭popen打开的文件流return n;
}// 获取语音线程
void *pget_voice(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};int len = 0;printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 循环读取串口数据while (1) {len = my_serialGetstring(serial_fd, buffer);printf("%s|%s|%d, len = %d\n", __FILE__, __func__, __LINE__, len);// 检测到特定数据,发出信号唤醒其他线程if (len > 0 && buffer[2] == 0x46) {printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);buffer[2] = 0x00;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);system(WGET_CMD);}}pthread_exit(0);
}// 发送语音线程
void *psend_voice(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}// buffer不为空时,通过串口发送数据(分类结果)if (NULL != buffer) {my_serialSendstring(serial_fd, buffer, 6);}pthread_exit(0);
}// 控制垃圾桶线程
void *popen_trash_can(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 根据垃圾类型控制PWMif (buffer[2] == 0x43) {		// 可回收垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}else if (buffer[2] == 0x41) {	// 干垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}else if (buffer[2] == 0x42) {	// 湿垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_write(PWM_WET_GARBAGE);delay(2000);pwm_stop(PWM_WET_GARBAGE);}else if (buffer[2] == 0x44) {	// 有害垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_stop(PWM_HAZARDOUS_GARBAGE);delay(2000);pwm_write(PWM_HAZARDOUS_GARBAGE);}pthread_exit(0);
}// 在线程中显示 OLED
void *poled_show(void *arg)
{// 分离线程,使其在退出时能够自动释放资源pthread_detach(pthread_self());// 初始化 OLEDmyoled_init();// 在 OLED 上显示垃圾分类结果oled_show(arg);// 退出线程	pthread_exit(0);
}// 垃圾分类线程
void *pcategory(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};char *category = NULL;pthread_t send_voice_tid, trash_tid, oled_tid;while (1) {printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);buffer[2] = 0x00;// 在执行wget命令之前添加调试输出printf("Executing wget command...\n");// 使用系统命令拍照system(WGET_CMD);// 在执行wget命令之后添加调试输出printf("Wget command executed.\n");// 判断垃圾种类if (0 == access(GARBAGE_FILE, F_OK)) {category = garbage_category(category);if (strstr(category, "干垃圾")) {buffer[2] = 0x41;}else if (strstr(category, "湿垃圾")) {buffer[2] = 0x42;}else if (strstr(category, "可回收垃圾")) {buffer[2] = 0x43;}else if (strstr(category, "有害垃圾")) {buffer[2] = 0x44;}else {buffer[2] = 0x45; // 未识别到垃圾类型}}else {buffer[2] = 0x45; // 识别失败}// 开垃圾桶开关pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer);// 开语音播报线程pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer);//oled显示线程pthread_create(&oled_tid, NULL, poled_show, (void *)buffer);// buffer[2] = 0x00;// 删除拍照文件remove(GARBAGE_FILE); }pthread_exit(0);
}void *pget_socket(void *arg)
{int server_fd = -1;				// 服务器 socket 文件描述符int client_fd = -1;				// 客户端 socket 文件描述符char buffer[6];					// 用于存储接收到的数据的缓冲区int nread = -1;					// 接收到的数据长度struct sockaddr_in client_addr;	// 客户端地址信息结构体int clen = sizeof(struct sockaddr_in);memset(&client_addr, 0, sizeof(struct sockaddr_in));// 初始化服务器 socketserver_fd = socket_init(IPADDR, IPPORT);printf("%s|%s|%d:server_fd = %d\n", __FILE__, __func__, __LINE__, server_fd);if (-1 == server_fd) {pthread_exit(0); // 初始化失败,退出线程}sleep(3); // 等待 socket 初始化完成while (1) {// 接受客户端连接client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &clen);// 配置 TCP KeepAlive 参数int keepalive = 1; 			// 开启TCP KeepAlive功能int keepidle = 5; 			// tcp_keepalive_time 3s内没收到数据开始发送心跳包int keepcnt = 3; 			// tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒int keepintvl = 3;			// tcp_keepalive_intvl 每3s发送一次心跳包setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));setsockopt(client_fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(keepidle));setsockopt(client_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof(keepcnt));setsockopt(client_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(keepintvl));printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));if (client_fd == -1) {perror("accept");continue; // 如果接受连接失败,继续下一次循环}while (1) {memset(buffer, 0, sizeof(buffer));// 从客户端接收数据nread = recv(client_fd, buffer, sizeof(buffer), 0); //n_read = read(c_fd, buffer, sizeof(buffer));printf("%s|%s|%d:nread = %d, buffer = %s\n", __FILE__, __func__, __LINE__, nread, buffer);// 根据接收到的数据执行相应的操作if (nread > 0) {if (strstr(buffer, "open")) {pthread_mutex_lock(&mutex);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);}if (strstr(buffer, "k1")) {pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}if (strstr(buffer, "k2")) {pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}if (strstr(buffer, "k3")) {pwm_write(PWM_WET_GARBAGE);delay(2000);pwm_stop(PWM_WET_GARBAGE);}if (strstr(buffer, "k4")) {pwm_stop(PWM_HAZARDOUS_GARBAGE);delay(2000);pwm_write(PWM_HAZARDOUS_GARBAGE);}}else if (0 == nread || -1 == nread) {break; // 如果接收到的数据长度为 0 或者出错,跳出循环}}close(client_fd); // 关闭客户端连接}pthread_exit(0); // 退出线程
}int main(int argc, char *argv[])
{int ret = -1;int len = 0;char *category = NULL;pthread_t get_voice_tid, category_tid, get_socket_tid;wiringPiSetup();// 初始化串口和垃圾分类模块garbage_init ();// 用于判断mjpg_streamer服务是否已经启动ret = detect_process ("mjpg_streamer");if (-1 == ret) {printf("detect process failed\n");goto END;}// 打开串口serial_fd = my_serialOpen (SERIAL_DEV, BAUD);if (-1 == serial_fd) {printf("open serial failed\n");goto END;}// 开语音线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_voice_tid, NULL, pget_voice, NULL);// 开网络线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_socket_tid, NULL, pget_socket, NULL);// 开阿里云交互线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&category_tid, NULL, pcategory, NULL);// 创建互斥锁和条件变量pthread_join(get_voice_tid, NULL);pthread_join(category_tid, NULL);pthread_join(get_socket_tid, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);// 关闭串口close(serial_fd);
END:// 释放垃圾分类资源garbage_final();return 0;
}

六、待定

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/208203.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32的四轴飞行器的控制系统(论文+源码)

1.系统设计 本次基于stm32单片机的四轴飞行器控制系统主要包括硬件和软件这两大部分&#xff0c;其中硬件部分是基于单片机的四轴飞行器控制系统实现的基石&#xff0c;其中主要STM32单片机负责整个系统功能的实现&#xff1b;NRF24L01无线模块负责对四轴飞行器的远程控制&…

【蓝桥杯软件赛 零基础备赛20周】第5周——高精度大数运算与队列

文章目录 1. 数组的应用–高精度大数运算1.1 Java和Python计算大数1.2 C/C高精度计算大数1.2.1 高精度加法1.2.2 高精度减法 2. 队列2.1 手写队列2.1.1 C/C手写队列2.1.2 Java手写队列2.1.3 Python手写队列 2.2 C STL队列queue2.3 Java队列Queue2.4 Python队列Queue和deque2.5 …

1688API接口系列,1688开放平台接口使用方案(商品详情数据+搜索商品列表+商家订单类)

1688商品详情接口是指1688平台提供的API接口&#xff0c;用于获取商品详情信息。通过该接口&#xff0c;您可以获取到商品的详细信息&#xff0c;包括商品标题、价格、库存、描述、图片等。 要使用1688商品详情接口&#xff0c;您需要先申请1688的API权限&#xff0c;并获取ac…

仿京东淘宝商品列表筛选组件:实现一个高效的侧边栏弹框筛选功能

仿京东淘宝商品列表筛选组件&#xff1a;实现一个高效的侧边栏弹框筛选功能 一、引言 随着电子商务的快速发展&#xff0c;用户体验成为了竞争的关键因素。在众多的电商网站中&#xff0c;如京东和淘宝&#xff0c;商品列表筛选功能为用户提供了便捷的途径来找到心仪的商品。本…

Clion+Ubuntu(WSL)+MySQL8.0开发环境搭建

1. 下载 MySQL 源码 访问 MySQL 官方网站&#xff08;MySQL :: Download MySQL Community Server&#xff09;并下载 MySQL 8.0 的源码包&#xff08;mysql-boost-8.0.31.tar.gz&#xff09;。 2. 安装编译依赖 1&#xff09;更换镜像源 参考&#xff1a;Linux Ubuntu 修改…

多线程06 单例模式,阻塞队列以及模拟实现

前言 上篇文章我们讲了wait和notify两个方法的使用.至此,多线程的一些基本操作就已经结束了,今天我们来谈谈多线程的一些简单应用场景. 单例模式 单例模式,顾名思义,只有一个实例的模式,我们有两种实现方式,分别是懒汉式和饿汉式,我们来分别给出代码. 饿汉式(此处的饿表示创建实…

使用 Go 构建高性能的命令行工具

命令行工具&#xff08;CLI&#xff09;在软件开发中扮演着重要的角色&#xff0c;尤其是在自动化工具、开发工具链和服务器管理等领域。Go 语言以其简洁性和高性能而闻名&#xff0c;非常适合用来创建强大且高效的 CLI 工具。本文将详细介绍如何使用 Go 语言来构建 CLI 应用&a…

Concurrent Security of Anonymous Credentials Light, Revisited

目录 摘要引言 摘要 我们重新审视了著名的匿名证书轻&#xff08;ACL&#xff09;方案&#xff08;Baldimtsi和Lysyanskaya&#xff0c;CCS’13&#xff09;的并发安全保证。该方案最初被证明在按顺序执行时是安全的&#xff0c;其并发安全性仍然是一个悬而未决的问题。Benham…

一致性Hash算法

Hash算法 哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值&#xff0c;这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。 Hash算法在安全加密领域MD5、SHA等加密算法&#xff0c;数据存储和查找的Hash表等方面均有应用。Hash表的数…

MOS管的静电击穿问题

MOS管输入电阻很高&#xff0c;为什么一遇到静电就不行了&#xff1f; 静电击穿&#xff1a;由于静电的积累导致电压超过了原本MOS的绝缘能力&#xff0c;导致电流突然增大的现象。 MOS管基础知识了解&#xff1a; G极(gate)—栅极&#xff0c;不用说比较好认 S极(source)—源…

分享一个国内可用的免费GPT4-AI提问AI绘画网站工具

一、前言 ChatGPT GPT4.0&#xff0c;Midjourney绘画&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而&#xff0c;GPT-4对普…

2017年五一杯数学建模A题公交车排班问题解题全过程文档及程序

2017年五一杯数学建模 A题 公交车排班问题 原题再现 随着徐州市经济的快速发展&#xff0c;公交车系统对于人们的出行扮演着越来越重要的角色。在公交车资源有限的情况下&#xff0c;合理的编排公交车的行车计划成为公交公司亟待解决的问题。以下给出公交车排班问题中的部分名…

vue+echarts实现依赖关系无向网络拓扑结图节点折叠展开策略

目录 引言 一、设计 1. 树状图&#xff08;不方便呈现节点之间的关系&#xff0c;次要考虑&#xff09; 2. 力引导依赖关系图 二、力引导关系图 三、如何实现节点的Open Or Fold 1. 设计逻辑 节点展开细节 节点收缩细节 代码实现 四、结果呈现 五、完整代码 引言 我…

重生奇迹MU再生原石

通过坎特鲁提炼之塔的NPC艾尔菲丝提炼成功就可以可获得再生宝石。 重生奇迹mu里的再生原石的用法&#xff1a; 1、打怪获得再生原石去提炼之塔&#xff08;进入坎特鲁遗址的141188位置的传送台&#xff09;。 2、找到&#xff08;艾儿菲丝&#xff09;把原石提炼成再生宝石。…

2016年五一杯数学建模C题二孩政策问题解题全过程文档及程序

2016年五一杯数学建模 C题 二孩政策问题 原题再现 多年来实施的严、紧计划生育政策对控制人口增长起到关键作用。在优生优育政策的指引下&#xff0c;我国人口质量显著提高&#xff0c;但也带来了不利影响&#xff0c;生育率偏低、男女比例失衡、人口老龄化情况严重等问题。2…

小程序如何进行一键修复

在使用小程序过程中&#xff0c;难免会遇到一些问题&#xff0c;比如程序崩溃、功能异常等等。这时&#xff0c;版本一键修复就显得尤为重要了。下面&#xff0c;我们就来介绍一下小程序如何进行版本一键修复。 一、什么是版本一键修复&#xff1f; 版本一键修复是指在小程序…

ELK---filebeat日志收集工具

elk---filebeat日志收集工具 filebeat是一个轻量级的日志收集工具&#xff0c;所使用的资源比logstash部署和启动时使用的资源小的多。 filebeat可以在非Java环境收集日志&#xff0c;它可以代替logstash在非Java环境上收集日志。 filebeat无法实现数据的过滤&#xff0c;一般…

Linux 调试工具:gdb

调试复习 调试可谓是 “贯穿” 了程序员的一生&#xff0c;调试的重要性&#xff0c;就不再赘述啦&#xff01;如果你还不知道什么是调试&#xff0c;可以看看 Windows 系统的 Visual Studio 是如何调试的&#xff1a;➡️ visual stuudio 使用调试技巧 下载调试软件 gdb yu…

java学习part29线程通信

139-多线程-线程间的通信机制与生产者消费者案例_哔哩哔哩_bilibili 1.等待唤醒 类似于golang的channel&#xff0c; 1.1用法 类似于go的wait()&#xff0c; 1.sleep和wait的一个重大区别是&#xff0c;sleep不会让线程失去同步监视器&#xff0c;而wait会释放 2.wait必须tr…

半监督语义分割综述

paper link&#xff1a;https://arxiv.org/pdf/2302.09899.pdf 1. Introduction 图像分割是最古老、研究最广泛的计算机视觉 (CV) 问题之一。图像分割是指将图像划分为不同的非重叠区域&#xff0c;并将相应的标签分配给图像中的每个像素&#xff0c;最终获得ROI区域位置及其类…