C++?手?jǐn)]簡(jiǎn)易服務(wù)器
本文沒(méi)有帶反射部分內(nèi)容,可以看我之前發(fā)的
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 8080 class 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 = ""; ? ? //攔截器 ? ? //先去攔截器映射表中尋找類名,沒(méi)有的話默認(rèn)使用基類 ? ? 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); ? ? ? ? } ? ? ? ? //反射結(jié)束 ? ? } ? ? 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; ? ? //檢測(cè)版本號(hào) ? ? 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 轉(zhuǎn) wchar ? ? ? ? int ?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; ? ? ? ? //重設(shè)大小 ? ? ? ? char* pAscii = new char[recv_len]; ? ? ? ? memset(pAscii, 0, sizeof(char) * recv_len); ? ? ? ? strncpy(pAscii, recv_buf, recv_len); ? ? ? ? string lrt(pAscii); ? ? ? ? //解析請(qǐng)求 ? ? ? ? Request req(lrt); ? ? ? ? Response resp; ? ? ? ? runRoute(req, &resp); ? ? ? ? cout << "請(qǐng)求地址:" << 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; ?? ?//路徑,若要訪問(wèn)的url startwith(path)此cookie攜帶 ?? ?string _path; ?? ?//網(wǎng)站域名 ?? ?string _domain; ?? ?string _version; ?? ?//生存時(shí)間 ?? ?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; }; //請(qǐng)求 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{ "" }; }; //響應(yīng) //結(jié)構(gòu) 狀態(tài)行, 響應(yīng)頭部, 空行, 響應(yīng)正文 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'); ?? ?//解析狀態(tài)行 ?? ?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'; ?? ?//解析請(qǐng)求頭 ?? ?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
使用方式如下
通過(guò)setRoute設(shè)置路由規(guī)則,類似于springboot中的注釋部分
通過(guò)setInterceptor設(shè)置攔截器規(guī)則,如果沒(méi)有設(shè)置的話,會(huì)默認(rèn)找基類
以上兩個(gè)設(shè)置之后還要再兩個(gè)macro文件中設(shè)置宏展開(kāi),否則反射找不到對(duì)應(yīng)的類,關(guān)于反射如何使用請(qǐng)看這個(gè)http://www.dbjr.com.cn/article/277497.htm
#include <iostream> #include <string> #include "ControllerMacro.h" #include "InterceptorMacro.h" #include "Server.h" using namespace std; using namespace myUtil; REFLEX_DECLARE REFLEX_INPERCEPTOR_DECLARE int 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; }
到此這篇關(guān)于C++ 手?jǐn)]簡(jiǎn)易服務(wù)器的文章就介紹到這了,更多相關(guān)C++ 簡(jiǎn)易服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++實(shí)現(xiàn)簡(jiǎn)單的HTTP服務(wù)器
- 使用C++制作簡(jiǎn)單的web服務(wù)器
- VSCode遠(yuǎn)程開(kāi)發(fā)調(diào)試服務(wù)器c/c++代碼
- C++簡(jiǎn)單QQ程序服務(wù)器端的實(shí)現(xiàn)代碼
- 使用C++制作簡(jiǎn)單的web服務(wù)器(續(xù))
- C++、python和go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單客戶端服務(wù)器代碼示例
- C/C++ 實(shí)現(xiàn)簡(jiǎn)易HTTP服務(wù)器的示例
- 基于C++編寫一個(gè)簡(jiǎn)單的服務(wù)器
相關(guān)文章
適合初學(xué)者練習(xí)的C語(yǔ)言實(shí)現(xiàn)三子棋小游戲
今天這篇文章主要介紹給大家分享一個(gè)適合初學(xué)者練習(xí)的利用C語(yǔ)言寫三子棋小游戲,用簡(jiǎn)單的C語(yǔ)言來(lái)實(shí)現(xiàn)小時(shí)候玩的三子棋游戲,下面是人機(jī)對(duì)戰(zhàn),當(dāng)然這個(gè)代碼的電腦對(duì)手是人工智障而不是人工智能 詳細(xì)內(nèi)容就請(qǐng)跟小編一起來(lái)閱讀下面文章內(nèi)容吧2021-10-10opencv4.5.4+VS2022開(kāi)發(fā)環(huán)境搭建的實(shí)現(xiàn)
本文主要介紹了opencv4.5.4+VS2022開(kāi)發(fā)環(huán)境搭建的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C++ 實(shí)現(xiàn)漢諾塔的實(shí)例詳解
這篇文章主要介紹了C++ 實(shí)現(xiàn)漢諾塔的實(shí)例詳解的相關(guān)資料,這里主要說(shuō)明C++中數(shù)據(jù)結(jié)構(gòu)的遞歸的應(yīng)用,需要的朋友可以參考下2017-08-08