TCP客户端服务器端通信(线程池版)

1、什么是监听套接字,和UDP相比,TCP为什么文件描述符变多了?

       在网络编程中,TCP和UDP是两种常见的传输协议,它们之间最大的不同之一在于连接的管理方式。为了更好地理解这个区别,我们可以用一个生动的比喻来说明。

        假设你在一家餐馆工作,其中张三负责把客人带到座位上,而李四和王五是服务员,他们负责为客人点菜和服务。张三的角色类似于TCP连接中的监听套接字。他的工作是确保当客户到达时,他们能够被快速、有效地分配给一个合适的服务员。

        在TCP协议中,监听套接字(就像张三)是独特的:它负责创建监听端口,通过这个端口,服务器可以接收到请求。当有新的连接请求时,该监听套接字的角色是“接客”,将请求转交给一个新的文件描述符(类似李四或王五),这个新的文件描述符负责具体的数据传输和处理。因此,虽然张三(监听套接字)数量是固定的,但却需要多个“服务员”来处理多个客户连接,即多个文件描述符。相比之下,UDP协议不需要这种复杂的连接管理机制,因为它是无连接的,不需要维护任何长时间的连接状态,因此它的文件描述符相对少。

2、如果现在还没写客户端,只写了服务器端,怎么测试当前服务器通信的时候会有别人来连我呢?工具:telnet 127.0.0.1 8888(底层默认tcp)

当你正在开发一个服务器应用程序,但还没有编写客户端时,你可能会想测试服务器的连接和通信功能。这时,我们可以使用一个简单的工具——telnet。假设你的服务器正在本地计算机上运行,并监听8888端口,你可以在命令行中输入以下命令来测试连接:

要检查当前活跃的网络连接,可以使用以下命令:

netstat -nltp 

服务器端代码写好了,直接用工具来测试。

#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include <string>
#include <arpa/inet.h>
#include <cstring>
#include <netinet/in.h>const int defaultfd=-1;
const std::string defaultip="0.0.0.0";
const int backlog=10;//一般不要设置的太大,后面解释
Log lg;
enum{SOCKET_ERR=2,BIND_ERR,Listen_ERR
};
class TcpServer
{
public:TcpServer(const uint16_t &port,const std::string &ip=defaultip):listensock_(defaultfd),port_(port),ip_(ip){};void InitServer(){listensock_=socket(AF_INET,SOCK_STREAM,0);if(listensock_<0){lg(Fatal,"errno:%d,errrstring:%s",errno,strerror(errno));exit(SOCKET_ERR);}lg(Info,"create socket success,listensock_:%d",listensock_);struct sockaddr_in local; //服务器信息memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(port_); //用户在构建服务器时就需要告诉我inet_aton(ip_.c_str(),&(local.sin_addr));local.sin_addr.s_addr=INADDR_ANY; //或者写成0if(bind(listensock_,(const sockaddr*)&local,sizeof(local))<0){lg(Fatal,"bind error,errno:%d,errrstring:%s",errno,strerror(errno));exit(BIND_ERR);}lg(Info,"bind success");//和UDP不一样的地方,设为监听状态 Tcp是面向链接的,服务器一般是比较被动的。服务器一直处于一种,一直在等待连接到来的状态if(listen(listensock_,backlog)<0){lg(Fatal,"errno:%d,errrstring:%s",errno,strerror(errno));exit(Listen_ERR);}}void Start(){lg(Info, "tcpserver is running....");while (true){// 1.获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);if (sockfd < 0){lg(Warning, "errno:%d,errrstring:%s", errno, strerror(errno));//获取连接失败,就直接再去获取continue;}//到底是谁连接的我uint16_t clientport=ntohs(client.sin_port); //网络转主机char clientip[32];std::string ip=inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));//把客户端的ip存到ipstr中//2.根据新连接进行通信// lg(Info,"get a new Link...,sockfd:%d,client ip:%s,client port:%d",sockfd,clientip,clientport);//version 1Service(sockfd,ip,clientport);//拿到客户端的端口和ip}}void Service(int sockfd,const std::string &clientip,uint16_t &clientport){char buffer[4096];//测试代码:你给我发什么我就给你响应什么while(true){ssize_t n=read(sockfd,buffer,sizeof(buffer));if(n>0){buffer[n]=0;std::cout<<"client say#"<<buffer<<std::endl;std::string echo_string="tpserver echo#";echo_string+=buffer;write(sockfd,echo_string.c_str(),echo_string.size()); //再写回去}}}~TcpServer(){}; 
private:int listensock_;uint16_t port_;std::string ip_;
};

测试:ctrl+] 进入    ctrl+] quit退出

 

发现客户端发的aaaaa,服务器端收到了。

问题1:要是客户端退出,服务器会怎么办?

服务器会读到0,服务中止,服务器端也直接退出

问题2:服务器向一个不存在的fd写入

signal(SIGPIPE,SIG_IGN);//防止出现写入的时候,向一个已经关闭的文件描述符写入的时候,此时连接没有意义,这时写时,os直接SIGPIPE掉

3、代码

TcpServer.hpp#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include <string>
#include <arpa/inet.h>
#include <cstring>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include<sys/wait.h>
#include<pthread.h>
#include "ThreadPool.hpp"
#include"Task.hpp"
#include<signal.h>
const int defaultfd=-1;
const std::string defaultip="0.0.0.0";
const int backlog=10;//一般不要设置的太大,后面解释
Log lg;
enum{SOCKET_ERR=2,BIND_ERR,Listen_ERR
};
class TcpServer;
class ThreadData//把TcpServer本身传进来
{
public:ThreadData(int fd,const std::string &ip,const uint16_t &port,TcpServer *t):sockfd(fd),clientip(ip),clientport(port),tsvr(t){}
public:int sockfd;std::string clientip;uint16_t clientport;TcpServer *tsvr;
};
class TcpServer
{
public:TcpServer(const uint16_t &port,const std::string &ip=defaultip):listensock_(defaultfd),port_(port),ip_(ip){};void InitServer(){listensock_=socket(AF_INET,SOCK_STREAM,0);if(listensock_<0){lg(Fatal,"errno:%d,errrstring:%s",errno,strerror(errno));exit(SOCKET_ERR);}lg(Info,"create socket success,listensock_:%d",listensock_);struct sockaddr_in local; //服务器信息memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(port_); //用户在构建服务器时就需要告诉我inet_aton(ip_.c_str(),&(local.sin_addr));local.sin_addr.s_addr=INADDR_ANY; //或者写成0if(bind(listensock_,(const sockaddr*)&local,sizeof(local))<0){lg(Fatal,"bind error,errno:%d,errrstring:%s",errno,strerror(errno));exit(BIND_ERR);}lg(Info,"bind success");//和UDP不一样的地方,设为监听状态 Tcp是面向链接的,服务器一般是比较被动的。服务器一直处于一种,一直在等待连接到来的状态if(listen(listensock_,backlog)<0){lg(Fatal,"errno:%d,errrstring:%s",errno,strerror(errno));exit(Listen_ERR);}}// void Service(int sockfd,const std::string &clientip,uint16_t &clientport)// {//     char buffer[4096];//     //测试代码:你给我发什么我就给你响应什么//     while(true)//     {//         ssize_t n=read(sockfd,buffer,sizeof(buffer));//         if(n>0)//         {//             buffer[n]=0;//             std::cout<<"client say#"<<buffer<<std::endl;//             std::string echo_string="tpserver echo#";//             echo_string+=buffer;//             write(sockfd,echo_string.c_str(),echo_string.size()); //再写回去//         }//         else if(n==0)//         {//             //lg(Info,"%s:%d quit,server close sockfd:%d",clientip,clientport,sockfd);//             break;//         }//         else//         {//             lg(Warning,"read Error...,sockfd:%d,client ip:%s,client port:%d",sockfd,clientip.c_str(),clientport);//         }//     }// }// static void* routine(void *args)//静态函数,把this传进来// {//     pthread_detach(pthread_self());//把自己设置为分离状态,主线程一直再获取新连接,创建出线程就不管了,让新线程进行任务处理//     ThreadData *td=static_cast<ThreadData *>(args);//     td->tsvr->Service(td->sockfd,td->clientip,td->clientport);//由该线程提供服务//     delete td;//提供完服务,申请的堆空间释放掉//     return nullptr;// }void Start(){signal(SIGPIPE,SIG_IGN);//防止出现写入的时候,向一个已经关闭的文件描述符写入的时候,此时连接没有意义,这时写时,os直接SIGPIPE掉ThreadPool<Task>::GetInstance()->Start();//启动线程池lg(Info, "tcpserver is running....");while (true){// 1.获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);if (sockfd < 0){lg(Warning, "errno:%d,errrstring:%s", errno, strerror(errno));//获取连接失败,就直接再去获取continue;}//到底是谁连接的我uint16_t clientport=ntohs(client.sin_port); //网络转主机char clientip[32];inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));//把客户端的ip存到ipstr中//2.根据新连接进行通信//lg(Info,"get a new Link...,sockfd:%d,client ip:%s,client port:%d",sockfd,ip,clientport);//version 1// Service(sockfd,ip,clientport);//拿到客户端的端口和ip// close(sockfd);//version 2 --多进程版,因为创建一个进程成本太高了// pid_t id=fork();// if(id==0)// {//     close(listensock_);//     if(fork()>0) exit(0);//     //子进程 什么都可以看到//     Service(sockfd,ip,clientport);//孙子进程,wait立马返回,父进程和孙子进程并发访问,不用管孙子,不用等孙子,儿子已经挂了,孙子会被系统领养//     close(sockfd);//     exit(0);// }// close(sockfd);// //父进程继续获取新连接 打开文件描述符,打开之后交给子进程,自己就关掉了,如果不关,系统中会有非常多的文件没有关闭// pid_t rid=waitpid(id,nullptr,0);// (void)rid;//version 3 多线程版本// ThreadData *td=new ThreadData(sockfd,ip,clientport,this);//this把当前对象传进来// pthread_t tid;// pthread_create(&tid,nullptr,routine,td);//version 4 线程池版Task t(sockfd,clientip,clientport);ThreadPool<Task>::GetInstance()->Push(t);}}~TcpServer(){}; 
private:int listensock_;uint16_t port_;std::string ip_;
};
ThreadPool.hpp
#pragma once#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>struct ThreadInfo
{pthread_t tid;std::string name;
};static const int defalutnum = 10;template <class T>
class ThreadPool
{
public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void Wakeup(){pthread_cond_signal(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsQueueEmpty(){return tasks_.empty();}std::string GetThreadName(pthread_t tid){for (const auto &ti : threads_){if (ti.tid == tid)return ti.name;}return "None";}public:static void *HandlerTask(void *args){ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);std::string name = tp->GetThreadName(pthread_self());while (true){tp->Lock();while (tp->IsQueueEmpty()){tp->ThreadSleep();}T t = tp->Pop();tp->Unlock();t();}}void Start(){int num = threads_.size();for (int i = 0; i < num; i++){threads_[i].name = "thread-" + std::to_string(i + 1);pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);}}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Push(const T &t){Lock();tasks_.push(t);Wakeup();Unlock();}static ThreadPool<T> *GetInstance(){if (nullptr == tp_) // ???{pthread_mutex_lock(&lock_);if (nullptr == tp_){std::cout << "log: singleton create done first!" << std::endl;tp_ = new ThreadPool<T>();}pthread_mutex_unlock(&lock_);}return tp_;}private:ThreadPool(int num = defalutnum) : threads_(num){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~ThreadPool(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);}ThreadPool(const ThreadPool<T> &) = delete;const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:std::vector<ThreadInfo> threads_;std::queue<T> tasks_;pthread_mutex_t mutex_;pthread_cond_t cond_;static ThreadPool<T> *tp_;static pthread_mutex_t lock_;
};template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;
TcpClient.cc
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
//./tcpclient serverip serverport
void Usage(const std::string &proc)
{std::cout << "\n\rUsage: " << proc << " port[1024+]\n" << std::endl;
}
int main(int argc,char* argv[])
{if(argc!=3){Usage(argv[0]);exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr)); // 字符串转为in_addrwhile (true)                                              // 每次翻译的时候都要重新建立连接,因为服务器每次只给我提供一次服务{int cnt = 5;int isreconnect = false;int sockfd = 0;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;return 1;}do{// tcp客户端要不要bind,要不要显示的bind?// 客户端需要绑定,不需要显示的绑定,将来再通信时需要端口号和ip标识自己的唯一性,当发出消息的时候,服务器才能把消息转过来,但是对于客户端来说// 端口号具体是几不重要,唯一就行,由os随机选择,根据你的需要随机选中,UDP首次发送数据的时候// 客户端向服务器发起连接,TCP中客户端发起connect时,进行自动随机bind,这个函数最后几个参数是要知道服务器的ipint n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){std::cerr << "connect error" << std::endl;isreconnect=true;cnt--;return 2;}else{break;}}while(cnt&&isreconnect);if(cnt==0){std::cerr<<"user offline..."<<std::endl;break;}//上面的while循环是连接,下面的while是提供服务// while(true)// {std::string message;// 连接成功,可以直接发消息std::cout << "Please enter@" << std::endl;std::getline(std::cin, message);int n = write(sockfd, message.c_str(), message.size());if (n < 0){std::cerr << "write error" << std::endl;break;}// 收到服务器消息char inbuffer[4096];n = read(sockfd, inbuffer, sizeof(inbuffer));if (n > 0){inbuffer[n] = 0;std::cout << inbuffer << std::endl;break;}close(sockfd);}// }return 0;
}
Main.cc
#include"TcpServer.hpp"
#include<iostream>
#include<memory>
#include <pthread.h>void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[1024+]\n" << std::endl;
};
//./tcpserver 8080
int main(int argc,char** argv)
{if(argc!=2){Usage(argv[0]);exit(1);}uint16_t port=std::stoi(argv[1]);std::unique_ptr<TcpServer>tcp_svr(new TcpServer(port));tcp_svr->InitServer();tcp_svr->Start();return 0;
}
Task.hpp
#pragma once
#include <iostream>
#include <string>
#include<unistd.h>
#include <unordered_map>
#include"Log.hpp"
#include "Init.hpp"
extern Log lg;
Init init;
class Task
{
public:Task(int sockfd, const std::string &clientip, uint16_t &clientport) : sockfd_(sockfd), clientip_(clientip), clientport_(clientport){}void run(){char buffer[4096];ssize_t n = read(sockfd_, buffer, sizeof(buffer));if (n > 0){buffer[n] = 0;std::cout << "client key#" << buffer << std::endl;std::string echo_string=init.translation(buffer);write(sockfd_, echo_string.c_str(), echo_string.size()); // 再写回去if(n<0){lg(Warning,"write error,errno:%d,errstring:%s",errno,strerror(errno));}}else if (n == 0){// lg(Info,"%s:%d quit,server close sockfd:%d",clientip,clientport,sockfd);//break;}else{lg(Warning, "read Error...,sockfd:%d,client ip:%s,client port:%d", sockfd_, clientip_.c_str(), clientport_);}//只处理一次close(sockfd_);}void operator ()(){run();}~Task(){}private:int sockfd_;std::string clientip_;uint16_t clientport_;
};
Log.hpp
#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};
Init.hpp
#pragma once
#include<iostream>
#include<string>
#include <unordered_map>
#include <fstream>
#include "Log.hpp"
extern Log lg;
const std::string dictname="./dict.txt";
const std::string sep=":";
//apple:苹果
static bool Split(std::string &s,std::string *part1,std::string *part2)
{auto pos=s.find(sep);if(pos==std::string::npos) return false;*part1=s.substr(0,pos);*part2=s.substr(pos+1);//从pos到结尾
}
class Init
{
public:Init(){std::ifstream in(dictname);if(!in.is_open()){lg(Fatal,"ifstream open %s error",dictname.c_str());exit(1);}std::string line;while(std::getline(in,line)){std::string part1,part2;Split(line,&part1,&part2);dict.insert({part1,part2});}in.close();}std::string translation(const std::string &key){auto iter=dict.find(key);if(iter==dict.end()) return  "Unknow";else return iter->second;}
private:std::unordered_map<std::string,std::string> dict;
};
Makefile
.PHONY:all
all:tcpserver tcpclient
tcpserver:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
tcpclient:TcpClient.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f tcpserver tcpclient

4、理解前台进程和后台进程

在操作系统中,程序可以在两种模式下运行:前台后台

 4.1什么叫前台进程?

        前台进程是与用户直接交互的进程。当你在终端中运行程序时(例如,执行./process),它默认是在前台运行,这意味着它会占用终端并接收来自键盘的输入。这种进程会阻塞终端输入,直到进程结束,所以在它运行期间,像lspwd这样的命令通常不会有反应。

下面是一个简单的C++程序运行在前台的示例:

process.cc
#include<iostream>
#include<string>
#include<unistd.h>
int main()
{while(true){std::cout<<"hello..."<<std::endl;sleep(1);}return 0;
}

 

4.2后台进程

有时,你可能希望程序在后台运行,以便不阻塞你的终端。这时你可以在命令后面加上符号&,例如: 

./process &

这样,程序就会在后台运行,你可以继续使用终端执行其他命令。

4.3切换前后台

如果需要将一个后台进程切换到前台,可以使用fg命令。例如fg 1会将后台任务列表中的第一个任务移至前台。  把后台进程提到前台   fg 1

 所以什么叫做前台,什么叫后台?

谁拥有键盘文件

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

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

相关文章

FPGA:如何编写优秀的技术文档

编写一份优秀的FPGA项目技术文档确实是一项挑战&#xff0c;尤其是在需要同时传达技术深度和可读性的情况下。以下是我在FPGA设计领域积累的一些经验和方法&#xff0c;希望能为你的技术文档编写提供一些指导&#xff1a; 1. 明确文档的目的和目标受众 目的&#xff1a;确定文…

2024年天津市职业院校技能大赛高职组 “信息安全管理与评估”样题第三阶段

&#xff08;四&#xff09;第三阶段竞小组&#xff08;赛项&#xff09;目&#xff08;300分&#xff09; 第三阶段竞赛内容是:网络安全渗透&#xff08;夺旗挑战赛CTF&#xff09; 本模块要求参赛者作为攻击方&#xff0c;运用所学的信息收集、漏洞发现、漏洞利用等渗透测试技…

微搭低代码AI组件单词消消乐从0到1实践

目录 1 为什么要开发单词消消乐2 需要具备什么功能3 采用什么技术方案实现4 逻辑设计4.1 数据结构设计4.2 游戏的核心逻辑4.3 数据设计 5 代码详解5.1 导入依赖5.2 定义函数组件5.3 数据初始化5.4 状态定义5.5 打乱解释的逻辑5.6 定义选择单词的函数5.7 定义选择解释的函数5.8 …

SpringCloud 与 SpringBoot版本对应关系,以及maven,jdk

目录 SpringCloud 与 SpringBoot各版本的对应关系 方式一 Learn 方式二 OverView SpringBoot与JDK、maven 容器等对应关系 SpringCloud 与 SpringBoot各版本的对应关系 SpringCloudSpringBootFinchley2.0.xFinchley.SR1Spring Boot >=2.0.3.RELEASE and <=2.0.9RELEAS…

泷羽sec学习打卡-shell命令6

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都 与本人无关,切莫逾越法律红线,否则后果自负 关于shell的那些事儿-shell6 if条件判断for循环-1for循环-2实践是检验真理的唯一标准 if条件判断 创建…

QT 中 sqlite 数据库使用

一、前提 --pro文件添加sql模块QT core gui sql二、使用 说明 --用于与数据库建立连接QSqlDatabase--执行各种sql语句QSqlQuery--提供数据库特定的错误信息QSqlError查看qt支持的驱动 QStringList list QSqlDatabase::drivers();qDebug()<<list;连接 sqlite3 数据库 …

万字长文解读深度学习——dVAE(DALL·E的核心部件)

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸 深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总 万字长…

【论文阅读】一名系统研究者的攀登之路

作者&#xff1a;陈海波 陈海波是操作系统、系统结构、并行与分布式系统方向大牛&#xff0c;上海交通大学大牛团队 学习体会&#xff1a; 计算机系统论文准备周期较长&#xff0c;十有八九都是在解决新问题的路上~ 因此学习大佬的学习经验&#xff0c;少踩坑&#xff0c;把主…

PyODBC: Python 与数据库连接的桥梁

PyODBC: Python 与数据库连接的桥梁 介绍 在现代的开发环境中&#xff0c;数据是核心要素之一。几乎所有的应用程序都需要与数据库进行交互。在 Python 中&#xff0c;pyodbc 是一个非常常用的库&#xff0c;它提供了一种简便的方法&#xff0c;通过 ODBC&#xff08;开放数据…

【Python】练习【24-12-8】

题目出处 《Python程序设计基础&#xff08;第2版&#xff09;》&#xff0c;李东方等 主编&#xff0c;电子工业出版社&#xff0c;北京&#xff0c;2020.1 第 3 章&#xff1a;《Python程序的基本流程控制》 题目描述 3、编写程序&#xff0c;产生两个10以内的随机整数&a…

五、docker的网络模式

五、docker的网络模式 5.1 Docker的四种网络模式 当你安装docker时&#xff0c;它会自动创建三个网络&#xff0c;可使用如下命令查看&#xff1a; [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 7390284b02d6 bridge bridge lo…

二叉树优选算法(一)

一、根据二叉树创建字符串 题目介绍&#xff1a; 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 "()" 表示&#xff0c;转化后需…

C++_关于异常处理throw-try-catch

文章目录 作用1. 无异常捕获2. 有异常捕获 作用 简单说&#xff0c;异常处理机制主要作用是让程序能够继续执行&#xff0c;或者以一种可控的方式终止&#xff0c;而非让程序因为错误直接崩溃 一个简单的动态数组类&#xff0c;来看看有异常捕获和无异常捕获的区别 1. 无异常…

如何使用 Python 实现多线程编程?

在Python中实现多线程编程&#xff0c;主要通过threading模块来完成。 这个模块提供了丰富的API用于创建和管理线程。多线程可以提高程序的响应性&#xff0c;并且对于I/O密集型任务&#xff08;如网络请求、文件读写等&#xff09;来说&#xff0c;可以显著减少等待时间。 由…

Java的封装、继承、多态

书接上文&#xff0c;我们聊完了Java的类和对象&#xff0c;有没有唤起你脑海的一些记忆呢&#xff0c;我们有了类和对象的基础之后&#xff0c;我们就可以衍生出来封装继承和多态。 封装 我理解一个东西&#xff0c;我一般会先想这个是什么&#xff0c;再是怎么用&#xff0…

【C#】新建窗体文件,Form、UserControl

从用途、功能性和架构方面进行描述。 1. 继承自 Form 的窗体&#xff08;通常是窗口&#xff09;&#xff1a; 在 C# 中&#xff0c;Form 是用于创建应用程序的主窗口或对话框窗口的类。当您继承自 Form 时&#xff0c;您创建的是一个完整的窗口&#xff0c;可以显示内容、与…

OSCP:我理解的Web环境知识

你需要特别关注以下模块所涵盖的知识点&#xff0c;因为它们在考试中出现的概率很高。 1、SQL 注入&#xff08;SQL Injection&#xff09; ●允许攻击者注入自定义的、潜在恶意的 SQL 代码&#xff0c;由底层数据库执行。 ●可能导致数据泄露或目标服务器上的远程代码执行&…

Java 转Scala的那些异同

引言 在这个数据爆炸的时代&#xff0c;大数据应用如雨后春笋般涌现。作为一名 Java 开发者&#xff0c;你可能会发现 Scala 这个新世界充满了诱惑。Scala 结合了面向对象和函数式编程的优点&#xff0c;尤其在大数据领域&#xff08;如 Apache Spark&#xff09;中表现得尤为…

Fiddler 5.21.0 使用指南:过滤浏览器HTTP(S)流量下(四)

概述 在上一篇文章中&#xff0c;我们介绍了一部分简单的过滤功能&#xff0c;已经可以帮助我们较为准确的定位到感兴趣的请求&#xff1b;提升我们的工作效率&#xff0c;我们可以通过设置更为复杂的过滤规则&#xff0c;精准到定位的我们想要的请求和响应信息。专注于分析对…

LabVIEW氢同位素单质气体定量分装系统

氢同位素单质气体在多个行业中有重要应用&#xff0c;如能源和化工。传统的分装方法面临精度和自动化程度不足的问题。为此&#xff0c;开发了一套基于LabVIEW和质量流量控制器的定量分装系统&#xff0c;提高分装精度和效率&#xff0c;同时减少资源浪费和环境污染。 项目背景…