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

C++ 手撸简易服务器(完善版本)

本文没有带反射部分内容,可以看我之前发的

Server.h

#pragma once#include <string>
#include <iostream>
#include <thread>
#include <unordered_map>
using namespace std;
#ifndef _SERVER_
#define _SERVER_#include <winsock.h>
#include "Net.h"
#include "Util.h"
#pragma comment(lib,"ws2_32.lib")NAME_SPACE_START(myUtil)#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 8080class Server {
public:Server();Server(const std::string& addr = SERVER_ADDR, const int& port = SERVER_PORT);~Server() {}
public:bool listen(const int& maxConnect = 1);void setRoute(const string& url, const string& className, const string& classFunName);void runRoute(const Request& req, Response* resp);void setInterceptor(const string& url, const string& InterceptorName);void close();
protected:bool Init();void threadFunc(SOCKET m_server);int sendTelegram(const SOCKET& accept, const string& info, int flags);
private:SOCKET m_server;SOCKADDR_IN m_add_in;//thread listenThread;int connectCount{ 0 };unordered_map<string, pair<string, string>> routeMap;unordered_map<string, string> interceptorMap;IniHelper iniHelper;
};NAME_SPACE_END()
#endif //!_SERVER_

Server.cpp

#include "Server.h"
#include <minwindef.h>
#include <string>
#include <winsock.h>
#include <iostream>
#include <thread>
#include <fstream>
#include "Net.h"
#include "Util.h"
#include "Reflex.h"
#include "CController.h"
#include "Interceptor.h"
using namespace std;NAME_SPACE_START(myUtil)Server::Server()
{m_add_in.sin_family = AF_INET;m_add_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);m_add_in.sin_port = htons(SERVER_PORT);
}Server::Server(const std::string& addr, const int& port)
{m_add_in.sin_family = AF_INET;m_add_in.sin_addr.S_un.S_addr = inet_addr(addr.c_str());m_add_in.sin_port = htons(port);
}bool Server::listen(const int& maxConnect)
{if (!Init()) {return false;}m_server = socket(AF_INET, SOCK_STREAM, 0);if (::bind(m_server, (sockaddr*)&m_add_in, sizeof(SOCKADDR)) == SOCKET_ERROR) {WSACleanup();return false;}if (::listen(m_server, maxConnect) < 0) {WSACleanup();return false;}thread listenThread(&Server::threadFunc, this, m_server);listenThread.join();return true;
}void Server::setRoute(const string& url, const string& className, const string& classFunName)
{routeMap.insert(pair<string, pair<string, string>>(url, pair<string, string>(className, classFunName)));
}void Server::runRoute(const Request& req, Response* resp)
{string url = req.getRequestStatus().Url;Reflex* factory = myUtil::Singleton<Reflex>::Instance();string interceptorName = "";string res = "";string content = "";//拦截器//先去拦截器映射表中寻找类名,没有的话默认使用基类auto interceptorIt = interceptorMap.find(url);if (interceptorIt != interceptorMap.end()) interceptorName = interceptorIt->second;Interceptor* inter = (Interceptor*)factory->createClass(interceptorName);if (inter == nullptr) inter = new Interceptor();if (inter->preHandle(req, *resp)) {//反射auto it = routeMap.find(url);if (it != routeMap.end()) {CController* cont = (CController*)factory->createClass(it->second.first);res = cont->Call<string, Request, Response*>(it->second.second, req, resp);}//反射结束}else {resp->setResponseStatus("HTTP", 1, 1, 404, "Forbidden");}if (url.find("favicon.ico") != string::npos) {content = getFile(iniHelper.getIniConfig("staticResource", "favicon_path", "./favicon.ico"));resp->setResponseHead("content-type", "image/x-icon");}else if(res != "") {try {content = getFile(res);}catch(exception ex){content = ex.what();}}resp->setResponseContent(content);auto list = resp->getCookie();for (auto item : list) {resp->setResponseHead("Set-Cookie", item.toString());}resp->setResponseHead("content-length", to_string(content.size()));resp->setResponseHead("Server", "C++MVC");inter->postHandle(req, *resp);
}void Server::setInterceptor(const string& url, const string& InterceptorName)
{interceptorMap.insert(pair<string, string>(url, InterceptorName));
}void Server::close()
{closesocket(m_server);WSACleanup();
}bool Server::Init()
{WORD ver = MAKEWORD(2, 2);WSADATA wsadata;int errFlag = -1;errFlag = WSAStartup(ver, &wsadata);if (errFlag != 0) return false;//检测版本号if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {WSACleanup();return false;}return true;}
void Server::threadFunc(SOCKET m_server)
{while (1) {SOCKADDR_IN m_acc_in;int len = sizeof(SOCKADDR);SOCKET m_accept = accept(m_server, (sockaddr*)&m_acc_in, &len);if (m_accept == SOCKET_ERROR) {continue;}int recv_len = 0;char recv_buf[10000];recv_len = recv(m_accept, recv_buf, 10000, 0);//char 转 wcharint  unicodeLen = ::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, NULL, 0);wchar_t* pUnicode = new  wchar_t[unicodeLen];memset(pUnicode, 0, unicodeLen * sizeof(wchar_t));::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, (LPWSTR)pUnicode, unicodeLen);wstring  rt = pUnicode;//重设大小char* pAscii = new char[recv_len];memset(pAscii, 0, sizeof(char) * recv_len);strncpy(pAscii, recv_buf, recv_len);string lrt(pAscii);//解析请求Request req(lrt);Response resp;runRoute(req, &resp);cout << "请求地址:" << req.getRequestStatus().Url << endl;sendTelegram(m_accept, resp.toString(), 0);closesocket(m_accept);}
}int Server::sendTelegram(const SOCKET& accept, const string& info, int flags)
{int res = send(accept, info.c_str(), info.size(), flags);return res;
}NAME_SPACE_END()

Interceptor.h

#pragma once
#include "Net.h"
#include "Reflex.h"
using namespace myUtil;
#ifndef _INTERCEPTOR_
#define _INTERCEPTOR_class Interceptor : public RObject {
public:virtual bool preHandle(const Request& request, const Response& response) { return true; }virtual void postHandle(const Request& request, const Response& response) {}virtual void afterCompletion(const Request& request, const Response& response) {}
};#endif //!_INTERCEPTOR_

indexInterceptor.h

#pragma once
#include "Interceptor.h"
class IndexInterceptor : public Interceptor {
public:bool preHandle(const Request& request, const Response& response) override {return false;}void postHandle(const Request& request, const Response& response) override {}void afterCompletion(const Request& request, const Response& response) override {}
};

InterceptorMacro.h

#pragma once
#include "Reflex.h"
#include "indexInterceptor.h"
#define REFLEX_INPERCEPTOR_DECLARE \
REGISTER_REFLEX(IndexInterceptor)

Cookie.h

#pragma once
#ifndef _COOKIE_
#define _COOKIE_
#include <string>
using namespace std;
class Cookie
{
public:Cookie() {}Cookie(const string& name, const string& value) :_name(name), _value(value) {_comment = "";_path = "";_domain = "";_version = "";_maxAge = 0;}string getNameValue() const;void setNameValue(const string& name, const string& value);void setComment(const string& comment);void setPath(const string& path);void setDomain(const string& domain);void setVersion(const string& version);void setMaxAge(const int& maxAge);string getComment() const;string getPath() const;string getDomain() const;string getVersion() const;int getMaxAge() const;string toString() const;
private:string _name;string _value;//注释string _comment;//路径,若要访问的url startwith(path)此cookie携带string _path;//网站域名string _domain;string _version;//生存时间int _maxAge{ 0 };
};#endif //!_COOKIE_

Cookie.cpp

#include "Cookie.h"string Cookie::getNameValue() const
{return _name + "=" + _value;
}void Cookie::setNameValue(const string& name, const string& value)
{_name = name;_value = value;
}void Cookie::setComment(const string& comment)
{_comment = comment;
}void Cookie::setPath(const string& path)
{_path = path;
}void Cookie::setDomain(const string& domain)
{_domain = domain;
}void Cookie::setVersion(const string& version)
{_version = version;
}void Cookie::setMaxAge(const int& maxAge)
{_maxAge = maxAge;
}string Cookie::getComment() const
{return _comment;
}string Cookie::getPath() const
{return _path;
}string Cookie::getDomain() const
{return _domain;
}string Cookie::getVersion() const
{return _version;
}int Cookie::getMaxAge() const
{return _maxAge;
}string Cookie::toString() const
{string res = getNameValue();if (_comment != "") res += ";comment=" + _comment;if (_path != "") res += ";Path=" + _path;if (_domain != "") res += ";Domain=" + _domain;if (_version != "") res += ";Version=" + _version;res += ";Max-Age=" + _maxAge;return res;
}

CController.h

#pragma once
#ifndef _CCONTROLLER_
#define _CCONTROLLER_
#include "Reflex.h"
using namespace myUtil;
class CController : public RObject
{
};
#endif //!_CCONTROLLER_

indexController.h

#pragma once
#include "CController.h"
#include "Net.h"
#include "Reflex.h"
using namespace myUtil;
class indexController : public CController
{
public:indexController() {}~indexController() {}string index(const Request& req, Response* resp);string test(const Request& req, Response* resp);
};

indexController.cpp

#include "indexController.h"
#include <fstream>
using namespace std;string indexController::index(const Request& req, Response* resp)
{resp->setResponseStatus("HTTP", 1, 1, 200, "OK");resp->setResponseHead("Content-Type", "text/html,charset=UTF-8");return "index.html";
}string indexController::test(const Request& req, Response* resp)
{resp->setResponseStatus("HTTP", 1, 1, 200, "OK");resp->setResponseHead("Content-Type", "text/html,charset=UTF-8");Cookie cookie("test", "test");cookie.setDomain("localhost");cookie.setMaxAge(10);cookie.setPath("/test");resp->setCookie(cookie);return "test.html";
}

ControllerMacro.h

#pragma once
#include "indexController.h"
#define REFLEX_DECLARE \
REGISTER_REFLEX(indexController)\
REGISTER_REFLEX_METHOD_ARGS(indexController, index, string, Request&, Response*)\
REGISTER_REFLEX_METHOD_ARGS(indexController, test, string, Request&, Response*)

Net.h

#pragma once
#ifndef _NET_
#define _NET_#include <string>
#include <wtypes.h>
#include <unordered_map>
#include "Util.h"
#include "Cookie.h"
using namespace std;NAME_SPACE_START(myUtil)#define BLACK "\r\n"
#define SPACE " "class Net {
public:virtual string toString() = 0;virtual vector<Cookie> getCookie() const = 0;virtual void setCookie(const Cookie& cookie) = 0;Net() {}
protected:vector<Cookie> _cookie;
};struct RequestStatus
{string RMethod;string Url;string ProName;short verHigh;short verLow;
};struct ResponseStatus
{string ProName;short verHigh;short verLow;short status;string statusWord;
};//请求
class Request : public Net {
public:Request();Request(const string& sourceStr);void setRequestStatus(const string& method = "GET", const string& url = "/", const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1);void setRequestHead(const string& headKey, const string& headValue);void setRequestContent(const string& content);RequestStatus getRequestStatus() const;string getRequestContent(const string& headKey) const;vector<Cookie> getCookie() const override;void setCookie(const Cookie& cookie) override;string toString() override;~Request() {}
private:RequestStatus _status;unordered_map<string, string> _RequestHead;string _RequestContent{ "" };
};//响应
//结构 状态行, 响应头部, 空行, 响应正文
class Response : public Net {
public:Response();void setResponseStatus(const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1, const short& status = 200, const string& word = "");void setResponseHead(const string& headKey, const string& headValue);void setResponseContent(const string& content);ResponseStatus getResponseStatus() const;string getResponseHeadByKey(const string& headKey) const;vector<Cookie> getCookie() const override;void setCookie(const Cookie& cookie) override;string toString() override;~Response();
private:ResponseStatus _status;unordered_map<string, string> _ResponseHead;string _ResponseContent{ "" };
};class Analyse {
public:static vector<string> getVectorBySplit(const string& source, const char& ch);static unordered_map<string, string> getMapBySplit(const string& source, const char& ch1,const char& ch2);static string makeVectorByChar(const vector<string>& v, const char& ch);static string makeMapByChars(const unordered_map<string, string>& m, const char& ch1, const char& ch2);
};NAME_SPACE_END()
#endif //!_NET_

Net.cpp

#include "Net.h"
NAME_SPACE_START(myUtil)Response::Response()
{_status.ProName = "HTTP";_status.verHigh = 1;_status.verLow = 1;_status.status = 200;_status.statusWord = "OK";
}void Response::setResponseStatus(const string& _proName, const short& _verHigh, const short& _verLow, const short& status, const string& word)
{_status.ProName = _proName;_status.verHigh = _verHigh;_status.verLow = _verLow;_status.status = status;_status.statusWord = word;
}void Response::setResponseHead(const string& headKey, const string& headValue)
{_ResponseHead.insert(pair<string, string>(headKey, headValue));
}void Response::setResponseContent(const string& content)
{_ResponseContent = content;
}ResponseStatus Response::getResponseStatus() const
{return _status;
}string Response::getResponseHeadByKey(const string& headKey) const
{auto it = _ResponseHead.find(headKey);if (it == _ResponseHead.end()) return "";return (*it).second;
}vector<Cookie> Response::getCookie() const
{return _cookie;
}void Response::setCookie(const Cookie& cookie)
{_cookie.push_back(cookie);
}string Response::toString()
{string res = "";res += _status.ProName + "/" + to_string(_status.verHigh) + "." + to_string(_status.verLow)+ SPACE + to_string(_status.status) + SPACE + _status.statusWord + BLACK;for (auto it = _ResponseHead.begin(); it != _ResponseHead.end(); it++) {res += (*it).first + ":" + SPACE + (*it).second + BLACK;}res += BLACK;res += _ResponseContent;return res;
}Response::~Response()
{
}Request::Request(const string& sourceStr)
{int i = 0;vector<string> reqGroup = Analyse::getVectorBySplit(sourceStr, '\n');//解析状态行vector<string> statuses = Analyse::getVectorBySplit(reqGroup[0], ' ');_status.RMethod = statuses.at(0);_status.Url = statuses.at(1);statuses.at(2).pop_back();vector<string> verInfo = Analyse::getVectorBySplit(statuses.at(2), '/');_status.ProName = verInfo.at(0);_status.verHigh = Analyse::getVectorBySplit(verInfo.at(1), '.').at(0).at(0) - '0';_status.verLow = Analyse::getVectorBySplit(verInfo.at(1), '.').at(1).at(0) - '0';//解析请求头for (i = 1; i < reqGroup.size(); i++) {if (reqGroup[i] == "\r")break;reqGroup[i].pop_back();vector<string> temp = Analyse::getVectorBySplit(reqGroup[i], ':');_RequestHead.insert(pair<string, string>(temp.at(0), temp.at(1)));}i++;for (i; i < reqGroup.size(); i++) {_RequestContent += reqGroup.at(i) + "\n";}
}void Request::setRequestStatus(const string& method, const string& url, const string& _proName, const short& _verHigh, const short& _verLow)
{_status.RMethod = method;_status.Url = url;_status.ProName = _proName;_status.verHigh = _verHigh;_status.verLow = _verLow;
}void Request::setRequestHead(const string& headKey, const string& headValue)
{_RequestHead.insert(pair<string, string>(headKey, headValue));
}void Request::setRequestContent(const string& content)
{_RequestContent = content;
}RequestStatus Request::getRequestStatus() const
{return _status;
}string Request::getRequestContent(const string& headKey) const
{return _RequestContent;
}string Request::toString()
{string res = "";res += _status.RMethod + SPACE + _status.Url + SPACE + _status.ProName + "/"+ to_string(_status.verHigh) + "." + to_string(_status.verLow) + BLACK;for (auto it = _RequestHead.begin(); it != _RequestHead.end(); it++) {res += (*it).first + ":" + SPACE + (*it).second + BLACK;}res += BLACK;res += _RequestContent;return res;
}vector<Cookie> Request::getCookie() const
{return _cookie;
}void Request::setCookie(const Cookie& cookie)
{_cookie.push_back(cookie);
}vector<string> Analyse::getVectorBySplit(const string& source, const char& ch)
{vector<string> res;string temp = "";for (int i = 0; i < source.size(); i++) {if (source[i] == ch) {res.push_back(temp);temp = "";}else {char ch = source[i];temp.push_back(ch);}}if (temp != "") res.push_back(temp);return res;
}unordered_map<string, string> Analyse::getMapBySplit(const string& source, const char& ch1, const char& ch2)
{unordered_map<string, string> res;vector<string> temp = getVectorBySplit(source, ch1);for (string str : temp) {vector<string> t = getVectorBySplit(str, ch2);if (t.size() != 2) continue;res.insert(pair<string, string>(t.at(0), t.at(1)));}return res;
}string Analyse::makeVectorByChar(const vector<string>& v, const char& ch)
{string res = "";for (auto str : v) {res += str + ch;}res.pop_back();return res;
}string Analyse::makeMapByChars(const unordered_map<string, string>& m, const char& ch1, const char& ch2)
{string res = "";for (auto it = m.begin(); it != m.end(); it++) {res += it->first + ch2 + it->second + ch1;}res.pop_back();return res;
}
NAME_SPACE_END()

config.ini

[staticResource]
favicon_path=./ico/favicon.ico

使用方式如下

通过setRoute设置路由规则,类似于springboot中的注释部分
通过setInterceptor设置拦截器规则,如果没有设置的话,会默认找基类
以上两个设置之后还要再两个macro文件中设置宏展开,否则反射找不到对应的类,关于反射如何使用请看这个
https://blog.csdn.net/weixin_43891802/article/details/129411364

#include <iostream>
#include <string>
#include "ControllerMacro.h"
#include "InterceptorMacro.h"
#include "Server.h"
using namespace std;
using namespace myUtil;REFLEX_DECLARE
REFLEX_INPERCEPTOR_DECLAREint main() {Server server("127.0.0.1", 8080);server.setRoute("/", "indexController", "index");server.setRoute("/test", "indexController", "test");//server.setInterceptor("/test", "IndexInterceptor");server.listen(2);return 0;
}

相关文章:

C++ 手撸简易服务器(完善版本)

本文没有带反射部分内容&#xff0c;可以看我之前发的 Server.h #pragma once#include <string> #include <iostream> #include <thread> #include <unordered_map> using namespace std; #ifndef _SERVER_ #define _SERVER_#include <winsock.h&…...

【Python入门第三十四天】Python丨文件处理

文件处理是任何 Web 应用程序的重要组成部分。 Python 有几个用于创建、读取、更新和删除文件的函数。 文件处理 在 Python 中使用文件的关键函数是 open() 函数。 open() 函数有两个参数&#xff1a;文件名和模式。 对于刚学Python的小伙伴&#xff0c;我给大家准备了2023…...

【Linux】写一个基础的bash

头文件#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/wait.h> #include<sys/stat.h> #include<string.h> #include<pwd.h> #include<dirent.h>分割输入的命令串字符串或参数内容为空则退出strtok( ,…...

图解如何一步步连接远程服务器——基于VScode

基于VScode连接远程服务器 安装Remote-SSH等插件 想要在vscode上连接远程服务器需要下载Remote-SSH系列插件&#xff1a; 直接在插件中搜索remote&#xff0c;即可找到&#xff0c;选择图片中的3个插件&#xff0c;点击install安装。 配置Remote-SSH 在这个步骤有多种操作…...

element - - - - - 你不知道的loading使用方式

求人不如求己 你不知道的loading使用方式1. 指令方式使用1.1 默认loading1.2 自定义loading1.3 整页加载2. 服务方式使用2.1 this.$loading的使用2.2 Loading.service的使用关于页面交互&#xff0c;最害怕的就是接口等待时间太长&#xff0c;用户体验不好。 而如何提高用户体…...

C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

目录 1、问题描述 2、VS中看不到有效的信息,尝试使用Windbg去分析 3、使用Windbg分析 4、最后...

IntelliJIDEA 常用快捷键

IntelliJIDEA 常用快捷键 Alt Enter 导入包&#xff0c;自动修正&#xff0c;自动创建变量名。 Ctrl Alt O 优化导入的类和包 Ctrl / 单行注释 (//) Ctrl Shift / 多行注释 (/* … */) 方法或类说明注释&#xff08;文档注释&#xff09; 在一个方法或类的开头&#xf…...

Python自动化抖音自动刷视频

环境准备 Python3.5以上Appium Server服务器Android SDK&#xff0c;需要用到adb服务需要依赖Appium-Python-Client组件库真机或者模拟器&#xff0c;推荐模拟器(真机一般安卓8版本以上了&#xff0c;appium对安卓8以上版本元素获取的兼容性不太好)JDK8环境 实现 确保adb服务…...

使用vite创建vue3工程

定义 什么是vite&#xff1f;-----新一代前端构建工具 优势 开发环境中&#xff0c;无需打包操作&#xff0c;可快速的冷启动---最牛的地方轻量快速的热重载&#xff08;HMR&#xff09;---一修改代码就局部刷新&#xff0c;webpack也具备&#xff0c;但vite更快真正的按需编…...

嵌入式学习笔记——STM32的时钟树

时钟树前言时钟树时钟分类时钟树框图LSI与LSEHSI、HSE与PLL系统时钟的产生举例AHB、APBx的时钟配置时钟树相关寄存器介绍1.时钟控制寄存器&#xff08;RCC_CR&#xff09;2.RCC PLL 配置寄存器 (RCC_PLLCFGR)3.RCC 时钟配置寄存器 (RCC_CFGR)4.RCC 时钟中断寄存器 (RCC_CIR)修改…...

Python学习(2)-NumPy矩阵与通用函数

文章首发于&#xff1a;My Blog 欢迎大佬们前来逛逛 1. NumPy矩阵 1.1 mat函数 matasmatrix asmatrix(data, dtypeNone):data&#xff1a;表示输入的数组或者字符串&#xff0c;使用‘&#xff0c;’分割列&#xff0c;使用‘&#xff1b;’分割行 创建两个普通的矩阵&…...

剑指 Offer II 035. 最小时间差

题目链接 剑指 Offer II 035. 最小时间差 mid 题目描述 给定一个 24小时制&#xff08;小时:分钟 "HH:MM"&#xff09;的时间列表&#xff0c;找出列表中任意两个时间的最小时间差并以分钟数表示。 示例 1&#xff1a; 输入&#xff1a;timePoints [“23:59”,“0…...

Spark SQL函数定义【博学谷学习记录】

1 如何使用窗口函数窗口函数格式:分析函数 over(partition by xxx order by xxx [asc|desc] [rows between xxx and xxx])学习的相关分析函数有那些? 第一类: row_number() rank() dense_rank() ntile()第二类: 和聚合函数组合使用 sum() avg() max() min() count()第三类: la…...

模拟实现STL容器之vector

文章目录前言1.大体思路2.具体代码实现1.类模板的创建2.构造函数1.无参构造2.拷贝构造 迭代器构造和给定n个val值构造以及析构函数3.空间扩容1.reserve2.resize4.操作符重载1.[ ]重载2.赋值运算符重载5.数据增加和删除1.尾插2.任意位置插入3.任意位置删除4.尾删6.一些其他接口3…...

ChatGPT-4.0 : 未来已来,你来不来

文章目录前言ChatGPT 3.5 介绍ChatGPT 4.0 介绍ChatGPT -4出逃计划&#xff01;我们应如何看待ChatGPT前言 好久没有更新过技术文章了&#xff0c;这个周末听说了一个非常火的技术ChatGPT 4.0&#xff0c;于是在闲暇之余我也进行了测试&#xff0c;今天这篇文章就给大家介绍一…...

Java反射(详细学习笔记)

Java反射 1. Java反射机制概述 Reflection&#xff08;反射&#xff09;是java被视为java动态语言的关键&#xff0c;反射机制允许程序在执行期间借助于Reflection API获取任何类的内部信息&#xff0c;并能直接操作任意对象的内部属性及方法。 Class c Class.forName(&quo…...

学习 Python 之 Pygame 开发魂斗罗(十二)

学习 Python 之 Pygame 开发魂斗罗&#xff08;十二&#xff09;继续编写魂斗罗1. 修改玩家扣减生命值2. 解决玩家下蹲子弹不会击中玩家而是直接让玩家死亡的问题3. 完善地图4. 增加产生敌人函数&#xff0c;解决一直产生敌人的问题5. 给玩家类增加计算玩家中心的方法继续编写魂…...

Linux下字符设备驱动开发以及流程介绍

文章目录1 - 字符设备介绍2 - 字符设备开发流程图3 - 字符设备开发流程具体讲解&#xff08;1&#xff09;设备编号的定义与申请【1】Linux主次设备号介绍【2】分配设备编号【3】释放主次设备号&#xff08;2&#xff09;定义file_operations结构体-初始化接口函数&#xff08;…...

Web自动化框架断言方法实现

前言1、设计用例方法关键字1.1、获取元素属性值2.1、断言2、代码实现2.1、实现获取元素属性值2.1.1 函数实现2.1.2 方法配置2.1.2 用例调试2.1.3 html属性2.2、实现断言2.2.1 函数2.2.2 方法配置2.2.3 用例调试1&#xff09;断言结果成功2&#xff09;断言结果失败前言 本文的…...

8大核心语句,带你深入python

人生苦短 我用python 又来给大家整点好东西啦~ 咱就直接开练噜&#xff01;内含大量代码配合讲解 python 安装包资料:点击此处跳转文末名片获取 1. for - else 什么&#xff1f;不是 if 和 else 才是原配吗&#xff1f; No&#xff0c;你可能不知道&#xff0c; else 是个…...

【批处理】- 批处理自动安装Mysql与Redis

前言 在全新环境中安装MySQL与Redis操作是挺麻烦的&#xff0c;于是就想使用脚本来自动安装&#xff0c;使用批处理进行一步到位的安装&#xff0c;后面还能使用工具进行打包成exe可执行文件&#xff0c;一键安装&#xff0c;最后能够更好的部署项目到windows系统的服务器。 …...

聊聊华为的工作模式

目录 一、试用期与加班工资 二、招聘 三、月度答辩和转正答辩 四、可信考试认证 五、接口人 六、问题缺陷单 七、代码检视 八、功能开发 九、出征海外 一、试用期与加班工资 一般而言&#xff0c;试用期持续的时间为3-6个月&#xff0c;工资、奖金都按正式员工的标准…...

燕山大学-面向对象程序设计实验-实验6 派生与继承:多重派生-实验报告

CSDN的各位友友们你们好,今天千泽为大家带来的是燕山大学-面向对象程序设计实验-实验5 派生与继承&#xff1a;单重派生-实验报告,接下来让我们一起进入c的神奇小世界吧,相信看完你也能写出自己的 实验报告!本系列文章收录在专栏 燕山大学面向对象设计报告中 ,您可以在专栏中找…...

分割两个字符串得到回文串[抽象--去除具体个性取共性需求]

抽象前言一、分割两个字符串得到回文串二、双指针总结参考文献前言 抽象去个性留共性&#xff0c;是因为具体个性对于解决问题是个累赘。少了累赘&#xff0c;直击需求&#xff0c;才能进行问题转换或者逻辑转换。 一、分割两个字符串得到回文串 二、双指针 // 限定死了&…...

【LeetCode】1609. 奇偶树、1122. 数组的相对排序

作者&#xff1a;小卢 专栏&#xff1a;《Leetcode》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 1609. 奇偶树 1609. 奇偶树 题目描述&#xff1a; 如果一棵二叉树满足下述几个条件&#x…...

【C++初阶】4. Date类的实现

如果下面博客有不理解的地方&#xff0c;可以查看源码&#xff1a;代码提交&#xff1a;日期类的实现 1. 构造函数的实现 由于系统实现的默认构造函数即便采用默认值的形式也只能存在1个固定的默认日期&#xff08;例如&#xff1a;1997-1-1&#xff09;。所以&#xff0c;构…...

ES6新特性--变量声明

可以使用let关键字来声明变量let a;let b,c;//同时声明多个变量let stu = 张三;let name =李四,age = 12;//声明变量的同时赋值 let关键字使用的注意事项(1).变量在声明的时候不可以重复,这也符合其他语言的变量声明规范 let name = 李四; let name = 张三;//这里开始报错,但…...

【Django】缓存机制

文章目录缓存的介绍Django的6种缓存方式开发调试缓存dummy.DummyCache内存缓存locmem.LocMemCache文件缓存filebased.FileBasedCache⭐️数据库缓存db.DatabaseCacheMemcache缓存memcached.MemcachedCacheMemcache缓存memcached.PyLibMCCacheDjango缓存的应用内存缓存cache_pag…...

我的创作纪念日——一年的时间可以改变很多

机缘 不知不觉来到CSDN已经创作一年了。打心底讲&#xff0c;对于在CSDN开始坚持创作的原因&#xff0c;我用一句话来概括最合适不过了——“无心插柳柳成荫” 为什么这么说呢&#xff1f; 这要从我的一篇博客说起——《输入命令Javac报错详解》&#xff1a; 那也是我第一次…...

Jetson Nano驱动机器人的左右两路电机

基于Jetson Nano板子搭建一个无人车&#xff0c;少不了减速电机驱动轮子滚动&#xff0c;那如何驱动呢&#xff1f;从Jetson.GPIO库文件来说&#xff0c;里面没有支持产生PWM的引脚&#xff0c;也就意味着Jetson nano没有硬件产生PWM的能力&#xff0c;所以我们不得不使用别的方…...