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

【网络编程】实现一个简单多线程版本TCP服务器(附源码)

00

TCP多线程

  • 🌵预备知识
    • 🎄 Accept函数
    • 🌲字节序转换函数
    • 🌳listen函数
  • 🌴代码
    • 🌱Log.hpp
    • 🌿Makefile
    • ☘️TCPClient.cc
    • 🍀TCPServer.cc
    • 🎍 util.hpp

🌵预备知识

🎄 Accept函数

accept 函数是在服务器端用于接受客户端连接请求的函数,它在监听套接字上等待客户端的连接,并在有新的连接请求到来时创建一个新的套接字用于与该客户端通信。

  • 下面是 accept 函数的详细介绍以及各个参数的意义:
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd: 是服务器监听套接字的文件描述符,通常是使用 socket 函数创建的套接字。accept 函数在该套接字上等待连接请求。

addr: 是一个指向 struct sockaddr 类型的指针,用于存储客户端的地址信息。当新连接建立成功后,客户端的地址信息将会被填充到这个结构体中。

addrlen: 是一个指向 socklen_t 类型的指针,它指示 addr 结构体的长度。在调用 accept 函数之前,需要将其初始化为 addr 结构体的大小,函数执行后会更新为实际的客户端地址长度。

返回值:如果连接成功建立,accept 函数将返回一个新的文件描述符,该文件描述符用于与客户端进行通信。如果连接失败,函数将返回 -1,并设置 errno 以指示错误原因。

  • accept 函数的工作原理如下:

当服务器的监听套接字接收到一个新的连接请求时,accept 函数会创建一个新的套接字用于与该客户端通信。
新的套接字会继承监听套接字的监听属性,包括 IP 地址、端口等。
accept 函数会填充 addr 结构体,以便获取客户端的地址信息。
服务器可以使用返回的新套接字与客户端进行通信。

  • 注意事项:

accept 函数在没有连接请求时会阻塞,直到有新的连接请求到来。
如果希望设置非阻塞模式,可以使用 fcntl 函数设置 O_NONBLOCK 属性。
在多线程或多进程环境下,需要注意 accept 函数的线程安全性,可以使用互斥锁等机制来保护。
综上所述,accept 函数在构建服务器程序时非常重要,它使服务器能够接受客户端的连接请求并创建新的套接字与客户端进行通信。

🌲字节序转换函数

在网络编程中,字节序问题很重要,因为不同的计算机体系结构可能使用不同的字节序,这可能导致在通信过程中的数据解释错误。为了在不同体系结构之间正确传递数据,需要进行字节序的转换。

  • 以下是一些常用的字节序转换函数:

ntohl 和 htonl: 这些函数用于 32 位整数的字节序转换。ntohl 用于将网络字节序转换为主机字节序,htonl 则相反,将主机字节序转换为网络字节序。

ntohs 和 htons: 这些函数用于 16 位整数的字节序转换。ntohs 用于将网络字节序转换为主机字节序,htons 则相反,将主机字节序转换为网络字节序。

这些函数通常用于在网络编程中处理套接字通信中的数据转换,以确保在不同平台上的正确数据交换。

  • 示例
#include <arpa/inet.h>int main() {uint32_t networkValue = 0x12345678;uint32_t hostValue = ntohl(networkValue); // 0x78563412 on a little-endian hostuint32_t convertedValue = htonl(hostValue); // 0x12345678 on a little-endian hostuint16_t networkPort = 0x1234;uint16_t hostPort = ntohs(networkPort); // 0x3412 on a little-endian hostuint16_t convertedPort = htons(hostPort); // 0x1234 on a little-endian hostreturn 0;
}

请注意,在使用这些函数时,需要包含 <arpa/inet.h> 头文件。这些函数通常在网络编程中用于正确处理字节序问题,以确保不同平台之间的数据传输正确。

🌳listen函数

在TCP通信中,服务端需要使用 listen 函数来监听连接请求。这是因为TCP是一种面向连接的协议,它采用客户端-服务端模型进行通信,通信双方需要先建立连接,然后进行数据的传输。监听的过程是为了等待客户端发起连接请求。

  • 具体原因如下:

建立连接: 在TCP通信中,通信双方需要通过三次握手建立连接。客户端通过 connect 函数向服务器发起连接请求,而服务端则需要通过 listen 函数来准备接收连接请求。

处理并发连接: 服务端可能会同时接收多个客户端的连接请求,而每个连接都需要为其分配一个独立的套接字。通过监听连接请求,服务端可以在一个循环中接受多个连接,为每个连接创建对应的套接字,从而实现并发处理多个客户端。

连接队列: listen 函数将连接请求存储在一个队列中,等待服务端逐个接受。这个队列称为“未完成连接队列”(backlog queue)。如果连接请求过多,超出了队列的长度,那么新的连接请求可能会被拒绝或被丢弃。

连接参数: listen 函数还可以指定一个参数,表示在未完成连接队列中可以容纳的连接请求数量。这个参数可以影响服务端处理并发连接的能力。

总之,TCP监听是为了等待客户端发起连接请求,建立连接,然后实现双方的数据传输。这种机制允许服务器处理多个客户端连接,实现高并发的网络服务。

  • 函数原型:
int listen(int sockfd, int backlog);
  • 参数说明:

sockfd:要进行监听的套接字描述符。
backlog:表示在未完成连接队列中可以容纳的连接请求数量。这个参数可以影响服务器处理并发连接的能力。通常情况下,系统会为这个值设置一个默认的最大值,但你也可以根据你的需求进行适当调整。
返回值:
如果函数调用成功,返回 0。
如果出现错误,返回 -1,并设置全局变量 errno 来指示错误类型。

使用步骤:

创建套接字并绑定地址。
调用 listen 函数将套接字标记为被动套接字,开始监听连接请求。
使用 accept 函数接受客户端连接请求,建立实际的连接。

  • 示例用法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>int main() {int listen_sock = socket(AF_INET, SOCK_STREAM, 0);if (listen_sock == -1) {perror("socket");exit(EXIT_FAILURE);}struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {perror("bind");exit(EXIT_FAILURE);}if (listen(listen_sock, 5) == -1) { // 开始监听,最多允许5个未完成连接perror("listen");exit(EXIT_FAILURE);}// 现在可以使用 accept 函数接受连接请求并建立连接close(listen_sock);return 0;
}

注意:listen 后的套接字仅能用于接受连接请求,不能用于读写数据。接收到的连接请求将在一个队列中等待,直到使用 accept 函数从队列中取出并建立连接。

🌴代码

🌱Log.hpp

#pragma once#include <cstdio>
#include <ctime>
#include <cstdarg>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <stdlib.h>#define DEBUG 0
#define NOTICE 1
#define WARINING 2
#define FATAL 3const char *log_level[]={"DEBUG", "NOTICE", "WARINING", "FATAL"};// logMessage(DEBUG, "%d", 10);
void logMessage(int level, const char *format, ...)
{assert(level >= DEBUG);assert(level <= FATAL);char *name = getenv("USER");char logInfo[1024];va_list ap; // ap -> char*va_start(ap, format);vsnprintf(logInfo, sizeof(logInfo)-1, format, ap);va_end(ap); // ap = NULLFILE *out = (level == FATAL) ? stderr:stdout;fprintf(out, "%s | %u | %s | %s\n", \log_level[level], \(unsigned int)time(nullptr),\name == nullptr ? "unknow":name,\logInfo);// char *s = format;// while(s){//     case '%'://         if(*(s+1) == 'd')  int x = va_arg(ap, int);//     break;// }
}

🌿Makefile

.PHONY:all
all:TCPClient TCPServerTCPClient: TCPClient.ccg++ -o $@ $^ -std=c++11 -lpthread
TCPServer:TCPServer.ccg++ -o $@ $^ -std=c++11 -lpthread.PHONY:clean
clean:rm -f TCPClient TCPServer

☘️TCPClient.cc

#include"util.hpp"
volatile bool quit=false;
static void Usage(std::string proc)
{std::cerr<<"Usage:\n\t"<<proc<<"serverip serverport "<<std::endl;std::cerr<<"Example:\n\t"<<proc<<"127.0.0.1 8080\n"<<std::endl;
}int main(int argc,char *argv[])
{if(argc!=3){Usage(argv[0]);exit(USAGE_ERR);}std::string serverip=argv[1];uint16_t serverport=atoi(argv[2]);//1.创建socket SOCK_STREAMint sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){std::cerr<<"socket :"<<strerror(errno)<<std::endl;exit(SOCKET_ERR);}//2.链接 //向服务器发起链接请求struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(server.sin_port);inet_aton(serverip.c_str(),&server.sin_addr);//2.2发起请求 connect自动会进行bindif(connect(sock,(const struct sockaddr*)&server,sizeof(server))!=0){//链接失败std::cerr<<"connect :"<<strerror(errno)<<std::endl;exit(CONN_ERR);}//链接成功std::cout<<" info :connect success :"<<sock<<std::endl;std::string message;while(!quit){message.clear();std::cout<<"请输入您的消息>>>>"<<std::endl;std::getline(std::cin,message);if(strcasecmp(message.c_str(),"quit")==0){//如果输入的是quit 直接退出程序quit=true; //设置成true 会把当前信息先执行发送到服务器 再进入while循环时条件不满直接退出}//从服务器接收到的消息ssize_t s=write(sock,message.c_str(),message.size());if(s>0){message.resize(1024);ssize_t s=read(sock,(char *)(message.c_str()),1024);if(s>0)message[s]=0;std::cout<<"Server Echo>>>"<<"message"<<std::endl;}else if (s <= 0){break;}}close(sock);return 0;
}

🍀TCPServer.cc

#include "util.hpp"
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
class ServerTcp;//先声明class ThreadData
{public:uint16_t clientPort_;//客户端端口号std::string clientip_;//客户端ipint sock_;ServerTcp *this_;ThreadData(uint16_t port, std::string ip, int sock,  ServerTcp *ts): clientPort_(port), clientip_(ip), sock_(sock),this_(ts){}};class ServerTcp
{public://构造和和析构函数ServerTcp(uint16_t port,const std::string &ip=""):port_(port),ip_(ip),listenSock_(-1){}~ServerTcp(){}public://初始化函数void init(){//第一步:创建套接字listenSock_=socket(PF_INET,SOCK_STREAM,0);if(listenSock_<0){//创建失败logMessage(FATAL,"socket:%s",strerror(errno)); //用日志打印错误信息exit(SOCKET_ERR);}//创建成功logMessage(DEBUG,"sockt:%s,%d",strerror(errno),listenSock_);//第二步 bind绑定//2.1填充服务器信息struct sockaddr_in local;memset(&local,0,sizeof(local));//设置0?/*可以确保将所有这些字段初始化为零,以避免在实际使用过程中出现未定义行为或不可预测的结果。*/local.sin_family=AF_INET;   /*如果 ip_ 为空,服务器将绑定到任意可用的本地IP地址。如果 ip_ 不为空,服务器将绑定到 ip_ 所代表的具体IP地址。*/ip_.empty()?(local.sin_addr.s_addr)=htons(INADDR_ANY):(inet_aton(ip_.c_str(),&local.sin_addr));//2.2if(bind(listenSock_,(const struct sockaddr*)&local,sizeof local)<0)//{//bind绑定失败logMessage(FATAL,"bind:%s",strerror(errno));exit(BIND_ERR);}//绑定成功logMessage(DEBUG,"bind:%S,%d",strerror(errno),listenSock_);//3.监听socketif(listen(listenSock_,5)<0){logMessage(FATAL,"listen:%s",strerror(errno));exit(LISTEN_ERR);}//监听成功logMessage(DEBUG,"listen:%S,%d",strerror(errno),listenSock_);//到这一步就等待运行 等待客户端链接}static void *threadRoutine(void *args){pthread_detach(pthread_self()); //设置线程分离ThreadData *td = static_cast<ThreadData*>(args);td->this_->tranService(td->sock_, td->clientip_, td->clientPort_);delete td;return nullptr;}//加载void loop(){while(true){struct sockaddr_in peer;socklen_t len=sizeof(peer);//获取链接 accept返回值??int serviceSock=accept(listenSock_,(struct sockaddr*)&peer,&len);if(serviceSock<0){//获取连接失败logMessage(WARINING,"Accept :%S[%d]",strerror(errno),serviceSock);continue;//获取失败 继续接收....}//获取客户端的基本信息 存储起来uint16_t peerPort=ntohs(peer.sin_port);std::string peerip=inet_ntoa(peer.sin_addr);//打印一下获取的客户端信息logMessage(DEBUG,"Aceept :%s|%s[%d],socket fd :%d",strerror(errno),peerip.c_str(),peerPort,serviceSock);// 5 提供服务, echo -> 小写 -> 大写// 5.0 v0 版本 -- 单进程 -- 一旦进入transService,主执行流,就无法进行向后执行,只能提供完毕服务之后才能进行accept// transService(serviceSock, peerIp, peerPort);// 5.1 v1 版本 -- 多进程版本 -- 父进程打开的文件会被子进程继承吗?会的// pid_t id = fork();// assert(id != -1);// if(id == 0)// {//     close(listenSock_); //建议//     //子进程//     transService(serviceSock, peerIp, peerPort);//     exit(0); // 进入僵尸// }// // 父进程// close(serviceSock); //这一步是一定要做的!// 5.1 v1.1 版本 -- 多进程版本  -- 也是可以的// 爷爷进程// pid_t id = fork();// if(id == 0)// {//     // 爸爸进程//     close(listenSock_);//建议//     // 又进行了一次fork,让 爸爸进程//     if(fork() > 0) exit(0);//     // 孙子进程 -- 就没有爸爸 -- 孤儿进程 -- 被系统领养 -- 回收问题就交给了系统来回收//     transService(serviceSock, peerIp, peerPort);//     exit(0);// }// // 父进程// close(serviceSock); //这一步是一定要做的!// // 爸爸进程直接终止,立马得到退出码,释放僵尸进程状态// pid_t ret = waitpid(id, nullptr, 0); //就用阻塞式// assert(ret > 0);// (void)ret;// 5.2 v2 版本 -- 多线程// 这里不需要进行关闭文件描述符吗??不需要啦// 多线程是会共享文件描述符表的!ThreadData *td = new ThreadData(peerPort, peerip, serviceSock, this);pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void*)td);// waitpid(); 默认是阻塞等待!WNOHANG// 方案1// logMessage(DEBUG, "server 提供 service start ...");// sleep(1);}}//提供服务函数 -----> 大小写转换void tranService(int sock,const std::string &clientip,uint16_t clientPort){assert(sock>=0);assert(!clientip.empty());assert(clientPort>=1024); //1~~1024端口为系统端口 不可轻易更改char inbuffer[BUFFER_SIZE];while(true){ssize_t s=read(sock,inbuffer,sizeof(inbuffer)-1); //-1是给\0留出一个位置if(s>0){inbuffer[s]='0';if(strcasecmp(inbuffer,"quit")==0){logMessage(DEBUG,"client quit----------%s[%d]",clientip.c_str(),clientPort);break;}logMessage(DEBUG,"Treans Before:%s[%d]>>>%s",clientip.c_str(),clientPort,inbuffer);//进行大小写转换for(int i=0;i<s;i++){if(isalpha(inbuffer[i])&&islower(inbuffer[i])){inbuffer[i]=toupper(inbuffer[i]);}}logMessage(DEBUG,"Trans after:%s[%d]>>>>%s",clientip.c_str(),clientPort,inbuffer);write(sock,inbuffer,strlen(inbuffer));//给客户端发送回去}else if(s==0){// pipe: 读端一直在读,写端不写了,并且关闭了写端,读端会如何?s == 0,代表对端关闭// s == 0: 代表对方关闭,client 退出logMessage(DEBUG, "client quit -- %s[%d]", clientip.c_str(), clientPort);break;}else{logMessage(DEBUG, "%s[%d] - read: %s", clientip.c_str(), clientPort, strerror(errno));break;}}// 只要走到这里,一定是client退出了,服务到此结束close(sock); // 如果一个进程对应的文件fd,打开了没有被归还,文件描述符泄漏!logMessage(DEBUG, "server close %d done", sock);}private:// sockint listenSock_;// portuint16_t port_;// ipstd::string ip_;
};static void Usage(std::string proc)
{std::cerr << "Usage:\n\t" << proc << " port ip" << std::endl;std::cerr << "example:\n\t" << proc << " 8080 127.0.0.1\n" << std::endl;}// ./ServerTcp local_port local_ip
int main(int argc, char *argv[])
{if(argc != 2 && argc != 3 ){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);std::string ip;if(argc == 3) ip = argv[2];ServerTcp svr(port, ip);svr.init();svr.loop();return 0;
}

🎍 util.hpp

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <ctype.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"#define SOCKET_ERR 1
#define BIND_ERR   2
#define LISTEN_ERR 3
#define USAGE_ERR  4
#define CONN_ERR   5#define BUFFER_SIZE 1024

大家可以拉下来自行测试…

🎋 🍃 🍂 🍁 🍄 🐚 💐 🌷 🌹 🥀 🌺 🌸 🌼 🌻

相关文章:

【网络编程】实现一个简单多线程版本TCP服务器(附源码)

TCP多线程 &#x1f335;预备知识&#x1f384; Accept函数&#x1f332;字节序转换函数&#x1f333;listen函数 &#x1f334;代码&#x1f331;Log.hpp&#x1f33f;Makefile☘️TCPClient.cc&#x1f340;TCPServer.cc&#x1f38d; util.hpp &#x1f335;预备知识 &…...

centos离线部署docker

有些内部环境需要离线部署&#xff0c;以下做一些备忘。 环境&#xff1a;centos7.9 准备文件&#xff1a; docker-20.10.9.tgz&#xff0c;下载地址 https://download.docker.com/linux/static/stable/x86_64/docker.service&#xff0c;内容见下文daemon.json&#xff0c;内…...

ffmpeg使用滤镜对视频进行处理播放

一、前言 在现代的多媒体处理中,视频和音频滤镜起着至关重要的作用。可以帮助开发者对视频和音频进行各种处理,如色彩校正、尺寸调整、去噪、特效添加等。而FFmpeg作为一个功能强大的开源多媒体框架,提供了丰富的滤镜库,使我们能够轻松地对多媒体文件进行处理和转换。 本…...

Ansible Handlers模块详解,深入理解Ansible Handlers 自动化中的关键组件

深入理解Ansible Handlers 自动化中的关键组件 在现代的IT环境中&#xff0c;自动化已经成为提高效率和减少错误的关键。Ansible作为一款流行的自动化工具&#xff0c;通过使用Playbooks来定义和执行任务。而Handlers作为Ansible的组件之一&#xff0c;在自动化过程中发挥着重要…...

threejs点击模型实现模型边缘高亮的选中效果--更改后提高帧率

先来个效果图 之前写的那个稍微有点问题&#xff0c;帧率只有30&#xff0c;参照官方代码修改后&#xff0c;帧率可以达到50了&#xff0c;在不全屏的状态下&#xff0c;帧率60 1.首先需要导入库 // 用于模型边缘高亮 import { EffectComposer } from "three/examples/js…...

RocketMQ 主备自动切换模式部署

目录 主备自动切换模式部署 Controller 部署​ Controller 嵌入 NameServer 部署​ Controller 独立部署​ Broker 部署​ 兼容性​ 升级注意事项​ 主备自动切换模式部署 该文档主要介绍如何部署支持自动主从切换的 RocketMQ 集群&#xff0c;其架构如上图所示&#xff…...

【MySQL】select相关

文章目录 迭代器distinct 关键字limit offset 关键字order by 列名 asc\descselect语句的执行顺序几点注意 迭代器 指向第一个元素 使用hasNext()进行判断后才进行取元素 resultSet&#xff1a;指向第一个元素前一个 distinct 关键字 去除一列中的重复元素 可以进行多行的去重…...

在Python中应用RSA算法实现图像加密:基于Jupyter环境的详细步骤和示例代码

一、引言 在当今的数字化社会中,信息安全问题备受关注。随着数字图像在生活中的应用越来越广泛,图像的安全性和隐私性也成为人们关心的焦点。如何在网络上安全地传输和存储图像已经成为一项重要的挑战。RSA(Rivest-Shamir-Adleman)算法作为一种被广泛应用的公钥密码体系,…...

Prometheus Blackbox Exporter 的 HTTP 探测指标中各个阶段的时间统计信息

在 Prometheus Blackbox Exporter 的 HTTP 探测指标中&#xff0c;probe_http_duration_seconds 指标包含各个阶段的时间统计信息。这些阶段代表了 HTTP 探测的不同阶段和指标。以下是各个阶段的含义&#xff1a; phase"dns_lookup"&#xff1a;这是指进行 DNS 查找…...

数据结构之时间复杂度-空间复杂度

大家好&#xff0c;我是深鱼~ 目录 1.数据结构前言 1.1什么是数据结构 1.2什么是算法 1.3数据结构和算法的重要性 1.4如何学好数据结构和算法 2.算法的效率 3.时间复杂度 3.1时间复杂度的概念 3.2大O的渐进表示法 【实例1】&#xff1a;双重循环的时间复杂度&#xf…...

新一代构建工具 maven-mvnd

新一代构建工具 maven-mvnd mvnd的前世今生下载安装 mvndIDEA集成 mvnd的前世今生 maven 作为一代经典的构建工具&#xff0c;流行了很多年&#xff0c;知道现在依然是大部分Java项目的构建工具的首选&#xff1b;但随着项目复杂度提高&#xff0c;代码量及依赖库的增多使得ma…...

构建Docker容器监控系统(2)(Cadvisor +Prometheus+Grafana)

Cadvisor产品简介 Cadvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行Cadvisor用户可以轻松的获取到当前主机上容器的运行统计信息&#xff0c;并以图表的形式向用户展示。 接着上一篇来继续 部署Cadvisor 被监控主机上部署Cadvisor容器…...

Leetcode.995 K 连续位的最小翻转次数

题目链接 Leetcode.995 K 连续位的最小翻转次数 rating : 1835 题目描述 给定一个二进制数组 n u m s nums nums 和一个整数 k k k 。 k k k位翻转 就是从 n u m s nums nums 中选择一个长度为 k k k 的 子数组 &#xff0c;同时把子数组中的每一个 0 0 0 都改成 1 1 1 …...

PHP8的跳转语句-PHP8知识详解

如果循环条件满足的时候&#xff0c;则程序会一直执行下去。如果需要强制跳出循环&#xff0c;则需要使用跳转语句来完成。PHP8的跳转语句包括break语句、continue语句和goto语句。 1、break语句 break语句的作用是完全终止循环&#xff0c;包括while、do…while、for、switch…...

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…...

【linux-keepalive】keepalive避免单点故障,高可用配置

keepalive: [rootproxy ~]# yum install -y keepalived [rootproxy ~]# vim /etc/keepalived/keepalived.conf global_defs {router_id proxy1 //设置路由ID号vrrp_iptables //不添加任何防火墙规则 } vrrp_instance V…...

测试网络模型的FLOPs和params

概念 FLOPS&#xff1a;注意全大写&#xff0c;是floating point operations per second的缩写&#xff0c;意指每秒浮点运算次数&#xff0c;理解为计算速度。是一个衡量硬件性能的指标。 FLOPs&#xff1a;注意s小写&#xff0c;是floating point operations的缩写&#xf…...

《树莓派项目实战》第十五节 使用L298N驱动板模块驱动双极42步进电机

目录 15.1 双极步进电机引脚介绍 15.2 连接到树莓派 15.3 编写代码驱动步进电机 在本节,我们将学习如何使用L298N驱动板驱动一个双极42步进电机。该项目涉及到的材料有: 树莓派...

基于短信宝API零代码实现短信自动化业务

场景描述&#xff1a; 基于短信宝开放的API能力&#xff0c;实现在特定事件&#xff08;如天气预警&#xff09;或定时自动发送短信&#xff08;本文以定时群发短信为例&#xff09;。通过Aboter平台如何实现呢&#xff1f; 使用方法&#xff1a; 首先创建一个IPaaS流程&…...

Qt应用开发(基础篇)——信号槽 Signals and Slots

一、前言 Qt成为我们今天拥有的灵活而舒适的工具&#xff0c;除了友好和能够快速开发设计师界面&#xff0c;信号槽机制是最大的核心特征&#xff0c;也是区别于其他开发框架最大的优势。 Qt的信号槽作用于两个对象之间的通信。当一个对象发生了改变&#xff0c;它希望其他关心…...

正则表达式--Notepad++常用的替换

原文网址&#xff1a;正则表达式--Notepad常用的替换_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Notepad使用正则表达式进行替换时的常用的一些示例。 服务器JSON的格式化 例1&#xff1a;将回车去掉&#xff0c;改为正确的JSON格式 搜索&#xff1a; ([^,])(\r)(\n)(\s) 替…...

ES6 对象合并

对象合并 在 JavaScript 中&#xff0c;可以使用不同的方法来合并对象的属性。这样可以将两个或多个对象的属性合并到一个新的对象中。这是在编程中常见的一种操作&#xff0c;尤其在处理配置、选项或数据更新时非常有用。 以下是几种常见的对象合并方法&#xff1a; 1. 使用…...

使用线性回归预测票房收入 -- 机器学习项目基础篇(10)

当一部电影被制作时&#xff0c;导演当然希望最大化他/她的电影的收入。但是我们能通过它的类型或预算信息来预测一部电影的收入会是多少吗&#xff1f;这正是我们将在本文中学习的内容&#xff0c;我们将学习如何实现一种机器学习算法&#xff0c;该算法可以通过使用电影的类型…...

一文读懂|RDMA原理

什么是DMA DMA全称为Direct Memory Access&#xff0c;即直接内存访问。意思是外设对内存的读写过程可以不用CPU参与而直接进行。我们先来看一下没有DMA的时候&#xff1a; 无DMA控制器时I/O设备和内存间的数据路径 假设I/O设备为一个普通网卡&#xff0c;为了从内存拿到需要…...

深入理解负载均衡原理及算法

1. 前言 在互联网早期,网络还不是很发达,上网用户少,流量相对较小,系统架构以单体架构为主。但如今在互联网发达的今天,流量请求动辄百亿、甚至上千亿,单台服务器或者实例已完全不能满足需求,这就有了集群。不论是为了实现高可用还是高性能,都需要用到多台机器来扩展服…...

44.实现爱尔兰B公式计算并输出表格(matlab程序)

1.简述 1.话务量定义 话务量指在一特定时间内呼叫次数与每次呼叫平均占用时间的乘积。 话务量反映了电话负荷的大小&#xff0c;与呼叫强度和呼叫保持时间有关。呼叫强度是单位时间内发生的呼叫次数&#xff0c;呼叫保持时间也就是占用时间。 话务量计算方法 话务量公式为…...

【Linux】-- 进程间通信

目录 一、进程间通信介绍 二、管道 1.什么是管道&#xff08;pipe&#xff09; 2.重定向和管道 &#xff08;1&#xff09;为什么要有管道的存在 &#xff08;2&#xff09;重定向和管道的区别 3.匿名管道 &#xff08;1&#xff09;匿名管道原理 &#xff08;2&…...

[PyTorch][chapter 48][LSTM -3]

简介&#xff1a; 主要介绍一下 sin(x)&#xff1a; 为 数据 cos(x): 为对应的label 项目包括两个文件 main.py: 模型的训练&#xff0c;验证&#xff0c;参数保存 lstm.py 模型的构建 目录&#xff1a; lstm.py main.py 一 lstm.py # -*- coding: utf-8 -*- "&q…...

xss csrf 攻击

介绍 xss csrf 攻击 XSS&#xff1a; XSS 是指跨站脚本攻击。攻击者利用站点的漏洞&#xff0c;在表单提交时&#xff0c;在表单内容中加入一些恶意脚本&#xff0c;当其他正常用户浏览页面&#xff0c;而页面中刚好出现攻击者的恶意脚本时&#xff0c;脚本被执行&#xff0c;从…...

如何使用win10专业版系统自带远程桌面公司内网电脑,从而实现居家办公?

使用win10专业版自带远程桌面公司内网电脑 文章目录 使用win10专业版自带远程桌面公司内网电脑 在现代社会中&#xff0c;各类电子硬件已经遍布我们身边&#xff0c;除了应用在个人娱乐场景的消费类电子产品外&#xff0c;各项工作也离不开电脑的帮助&#xff0c;特别是涉及到数…...

安徽做网站的公司/手机百度官网

select * from chenxxlevel where usercode 0000000001 for update;--若这条语句不能修改的话&#xff0c;要加RowID,如下这条sql&#xff1a;后面加for update即可。 转载于:https://www.cnblogs.com/hl3292/archive/2010/11/04/1869232.html...

做网站切图软件/搜索引擎营销的概念

采用的是黑金的板子 1、实验目的这一次的实验的目的就是使用FPGA上的按键能够控制上面的LED灯的亮灭 2、实验理解step1 能够检测到按键的变化 step2 将 检测到的按键变化-----能够通过判断到这个按键发生了变化 &#xff08;消抖的问题) -- 对应到led的灯的亮灭上 3、开始…...

wordpress排版界面/最近新闻热点国家大事

设置步骤: 1.勾选 Request Headers 中的 Hide if url contains 过滤项 2.贴入下方正则表达式 REGEX:(?insx)/[^?/]*.(css|ico|jpg|png|gif|bmp|wav)(?.*)?$ REGEX: 表示启用正则表达式 (?insx) 设置正则解释的规则, 忽略大小写等. 此表达式表示过滤掉 url 中包括 css, ico…...

网站开发遇到的难题/seo精灵

作者简介 任坤&#xff0c;现居珠海&#xff0c;先后担任专职 Oracle 和 MySQL DBA&#xff0c;现在主要负责 MySQL、mongoDB 和 Redis 维护工作。 背景 MySQL 版本&#xff1a;5.6.29&#xff0c;普通主从 OS&#xff1a;CentOS 6.8 最近一段时间线上某实例频繁报警CPU飙高…...

公司网站公司/网络舆情监控系统

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请注明出处。 https://blog.csdn.net/twilight_karl/article/details/77587740 查看进程 ps ps aux查看所有进程&#xff0c;使用BSD操作系统格式 ps -le 查看系统所有进程&#xff0c;使用Linux标准命令格式 参数 - a…...

零售客户电商网站登录/seo单页面优化

学习嵌入式的Nandflash时编写完代码后make执行后发现如下错误&#xff1a; start.s: Warning: end of file not at end of a line; newline inserted start.s:14: Error: no such instruction: ldr sp,0x1000 经过多次修改代码尝试&#xff0c;发现是文件的后缀名导致的&#…...