C++實(shí)現(xiàn)HTTP服務(wù)的示例代碼
一、C++Web服務(wù)器(核心代碼WebServer.cpp)
要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的C++Web服務(wù)器,支持GET和POST請(qǐng)求,同時(shí)能夠提供靜態(tài)文件(如JavaScript、CSS和圖片文件)。
#include <iostream> #include <string> #include <sstream> #include <fstream> #include <unordered_map> #include <netinet/in.h> #include <unistd.h> #include <sys/stat.h> using namespace std; #define PORT 8080 // 端口號(hào) #define BUFFER_SIZE 4096 // 緩沖區(qū)大小 //根據(jù)文件拓展名返回適當(dāng)?shù)腃ontent-Type std::string getContentType(const std::string &path){ if(path.ends_with(".html")) return "text/html"; if(path.ends_with(".css")) return "text/css"; if(path.ends_with(".js")) return "application/javascript"; if(path.ends_with(".png")) return "image/png"; if(path.ends_with(".jpg")) return "image/jpeg"; if(path.ends_with(".jpeg")) return "image/jpeg"; if(path.ends_with(".gif")) return "image/gif"; return "text/plain"; } //讀取靜態(tài)文件 std::string readFile(const std::string &path){ //創(chuàng)建一個(gè)輸入文件流對(duì)象,以二進(jìn)制模式打開(kāi)指定路徑的文件 std::ifstream file(path,std::ios::binary); //檢查文件是否成功打開(kāi) if(!file.is_open()){ perror("file open failed"); //如果打開(kāi)失敗返回空字符串 return ""; } //創(chuàng)建一個(gè)輸出字符串流對(duì)象,用于將文件內(nèi)容讀取到字符串 std::ostringstream ss; //使用輸出字符串流對(duì)象的rdbuf()將文件內(nèi)容讀取到字符串中 //這實(shí)際上是將文件流中的所有字節(jié)復(fù)制到字符串流的緩沖區(qū)中 ss<<file.rdbuf(); //將字符串流的內(nèi)容轉(zhuǎn)換為std::string并返回 return ss.str(); } //判斷文件是否存在 bool fileExists(const std::string &path){ struct stat buffer; return stat(path.c_str(), &buffer)==0; } int main() { // 創(chuàng)建套接字 int server_fd, new_socket; // 地址結(jié)構(gòu)體 struct sockaddr_in address; int opt=1; // 設(shè)置套接字選項(xiàng) int addlen = sizeof(address);// 地址結(jié)構(gòu)體長(zhǎng)度 char buffer[BUFFER_SIZE] = {0}; // 緩沖區(qū) if ((server_fd = socket(AF_INET, SOCK_STREAM, 0))==0){ perror("socket failed"); exit(EXIT_FAILURE); } //設(shè)置端口復(fù)用 //如果你不是用SO_REUSEADDR,服務(wù)器程序關(guān)閉后,可能會(huì)出現(xiàn)“Address already in use” 錯(cuò)誤 //尤其是當(dāng)你嘗試在同一個(gè)端口上重新啟動(dòng)服務(wù)器時(shí),這是因?yàn)門(mén)CP連接可能會(huì)保持TIME_WAIT的狀態(tài)一段時(shí)間 //而SO_REUSEADDR允許套接字在這種狀態(tài)下重新綁定到另一個(gè)端口 if(setsoocketopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))){ perror("setsoocketopt failed"); exit(EXIT_FAILURE); } //配置服務(wù)器地址 addrss.sin_family = AF_INET; addrss.sin_addr.s_addr = INADDR_ANY; addrss.sin_port = htons(PORT); //綁定套接字 if(bind(server_fd, (struct sockaddr *)&address, addlen)<0){ perror("bind failed"); exit(EXIT_FAILURE); } //監(jiān)聽(tīng)請(qǐng)求 if(listen(server_fd, 3)<0){ perror("listen failed"); exit(EXIT_FAILURE); } cout<<"WebServer is running on port"<<PORT<<"....\n"; while(true) { //接受客戶端連接 if((new_socket=accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addlen))<0){ perror("accept failed"); exit(EXIT_FAILURE); } //讀取客戶端請(qǐng)求 read(new_socket, buffer, BUFFER_SIZE); cout<<"Request received :\n"<<buffer<<endl; //解析Http請(qǐng)求 //這段代碼是解析Http請(qǐng)求中提取 請(qǐng)求方法、路徑和Http版本。如下: //第一次提取method,得到:GET //第二次提取path,得到:/index.html //第三次提取version,得到:HTTP/1.1 std::istringstream request(buffer); std::string method , path , version; request>>method>>path>>version; //默認(rèn)首頁(yè) if(path=="/") { path="/index.html"; } //構(gòu)建文件路徑 std::string filePath ="."+path; //處理GET請(qǐng)求 if(method=="GET"){ if(fileExists(filePath)){//文件存在 std::string content = readFile(filePath);//讀取文件內(nèi)容 std::string contentType = getContentType(filePath);//獲取文件類型 std::ostringstream response; // 構(gòu)建響應(yīng) response<<"HTTP/1.1 200 OK\r\n" <<"Content-Type:"<<contentType<<"\r\n" <<"Content-Length:"<<content.length()<<"\r\n" <<"\r\n" <<content;//響應(yīng)頭和響應(yīng)體 response<<content; //發(fā)送響應(yīng) send(new_socket, response.str().c_str(), response.str().length(), 0); }else{ //404 NOT FOUND std::string notFound="HTTP/1.1 404 Not Found\r\n\r\n404 Not Found"; send(new_socket, notFound.c_str(), notFound.length(), 0); } } else if(method=="POST"){//處理POST請(qǐng)求 //簡(jiǎn)單的響應(yīng)客戶端的POST請(qǐng)求(可以根據(jù)需要解析POST請(qǐng)求) std::string response="HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nPOST request"; send(new_socket, response.c_str(), response.length(), 0); }else{ //405 METHOD NOT ALLOWED std::string notAllowed="HTTP/1.1 405 Method Not Allowed\r\n\r\n405 Method Not Allowed"; send(new_socket, notAllowed.c_str(), notAllowed.length(), 0); } //關(guān)閉連接 close(new_socket); } //釋放資源,關(guān)閉服務(wù)器套接字 close(server_fd); return 0; }
二、靜態(tài)文件結(jié)構(gòu)
- 確保你的HTML、CSS、JS和圖片文件都存放在與可執(zhí)行程序相同的目錄下或適當(dāng)?shù)淖幽夸浿?,例如?/li>
./index.html ./style.css ./script.js ./images/example.jjpg
假設(shè)HTL文件是這樣的:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>這是一個(gè)簡(jiǎn)單的WebServer</title> <style> body{ font-family: Arial,sans-serif; background-color: #f4f4f9; color: #333; margin: 0; padding: 0; } header{ background-color: #4CAF50; color: white; padding: 10px 0; } h1{ margin: 0; } p{ font-size: 1.2em; margin: 20px auto; width: 80%; } footer{ position: fixed; bottom: 0; width: 100%; background-color: #4CAF50; color: white; padding: 10px 0; } </style> </head> <body> <header> <h1>這是一個(gè)簡(jiǎn)單的WebServer</h1> </header> <main> <p>這是一個(gè)簡(jiǎn)單的WebServer,你可以在這里放置一些內(nèi)容。</p> <br/> <img src="23.png" alt="C++測(cè)試"> </main> <footer> <p> ©2025 My WebServer By HuJiaHang </p> </footer> </body> </html>
三、編譯和運(yùn)行
- 編譯
g++ -std=c++20 WebServer.cpp -o WebServer //使用C++20標(biāo)準(zhǔn),是因?yàn)閟td::string::ends_with()是C++20引入的功能
- 運(yùn)行:執(zhí)行編譯好的WebServer程序
./WebServer
四、訪問(wèn)測(cè)試
使用瀏覽器訪問(wèn)http://localhost:8080,可以獲取靜態(tài)HTML頁(yè)面、CSS樣式、JavaScript腳本和圖片
注意:如果使用的是云服務(wù)器,就必須要在安全組中放開(kāi)端口
以下是我的測(cè)試
到此這篇關(guān)于C++實(shí)現(xiàn)HTTP服務(wù)的示例代碼的文章就介紹到這了,更多相關(guān)C++ HTTP服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)古代時(shí)辰計(jì)時(shí)與現(xiàn)代時(shí)間換算
這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)古代時(shí)辰計(jì)時(shí)與現(xiàn)代時(shí)間換算,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-03-03C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例
這篇文章主要介紹了C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握這樣的知識(shí),需要的朋友可以參考下2017-10-10C++通過(guò)循環(huán)實(shí)現(xiàn)猜數(shù)字小游戲
這篇文章主要為大家詳細(xì)介紹了C++通過(guò)循環(huán)實(shí)現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09C語(yǔ)言模擬實(shí)現(xiàn)庫(kù)函數(shù)詳解
C語(yǔ)言庫(kù)函數(shù)是把自定義函數(shù)放到庫(kù)里,是別人把一些常用到的函數(shù)編完放到一個(gè)文件里,供程序員使用,下面讓我們一起來(lái)詳細(xì)了解它2022-07-07C++中的取余函數(shù)remainder與fmod詳解
這篇文章主要為大家詳細(xì)介紹了C++中的取余函數(shù)remainder、fmod的具體使用以及自編的remainder及fmod,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2023-05-05利用OpenCV實(shí)現(xiàn)局部動(dòng)態(tài)閾值分割
這篇文章主要為大家詳細(xì)介紹了利用OpenCV實(shí)現(xiàn)局部動(dòng)態(tài)閾值分割,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01C語(yǔ)言實(shí)現(xiàn)病例管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)病例管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01