天天開心!!!
閱讀本篇文章之前,請先閱讀HTTP基礎知識
傳送門----> HTTP基礎知識
文章目錄
- 一、C++Web服務器(核心代碼WebServer.cpp)
- 二、靜態文件結構
- 三、編譯和運行
- 四、訪問測試
一、C++Web服務器(核心代碼WebServer.cpp)
要實現一個簡單的C++Web服務器,支持GET和POST請求,同時能夠提供靜態文件(如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 // 端口號#define BUFFER_SIZE 4096 // 緩沖區大小//根據文件拓展名返回適當的Content-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";}//讀取靜態文件
std::string readFile(const std::string &path){//創建一個輸入文件流對象,以二進制模式打開指定路徑的文件std::ifstream file(path,std::ios::binary);//檢查文件是否成功打開if(!file.is_open()){perror("file open failed");//如果打開失敗返回空字符串return "";}//創建一個輸出字符串流對象,用于將文件內容讀取到字符串std::ostringstream ss;//使用輸出字符串流對象的rdbuf()將文件內容讀取到字符串中//這實際上是將文件流中的所有字節復制到字符串流的緩沖區中ss<<file.rdbuf();//將字符串流的內容轉換為std::string并返回return ss.str();}//判斷文件是否存在
bool fileExists(const std::string &path){struct stat buffer;return stat(path.c_str(), &buffer)==0;
}int main() {// 創建套接字int server_fd, new_socket;// 地址結構體struct sockaddr_in address;int opt=1; // 設置套接字選項int addlen = sizeof(address);// 地址結構體長度char buffer[BUFFER_SIZE] = {0}; // 緩沖區if ((server_fd = socket(AF_INET, SOCK_STREAM, 0))==0){perror("socket failed");exit(EXIT_FAILURE);}//設置端口復用//如果你不是用SO_REUSEADDR,服務器程序關閉后,可能會出現“Address already in use” 錯誤//尤其是當你嘗試在同一個端口上重新啟動服務器時,這是因為TCP連接可能會保持TIME_WAIT的狀態一段時間//而SO_REUSEADDR允許套接字在這種狀態下重新綁定到另一個端口if(setsoocketopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))){perror("setsoocketopt failed");exit(EXIT_FAILURE);}//配置服務器地址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);}//監聽請求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);}//讀取客戶端請求read(new_socket, buffer, BUFFER_SIZE);cout<<"Request received :\n"<<buffer<<endl;//解析Http請求//這段代碼是解析Http請求中提取 請求方法、路徑和Http版本。如下://第一次提取method,得到:GET//第二次提取path,得到:/index.html//第三次提取version,得到:HTTP/1.1std::istringstream request(buffer);std::string method , path , version;request>>method>>path>>version;//默認首頁if(path=="/"){path="/index.html";}//構建文件路徑std::string filePath ="."+path;//處理GET請求if(method=="GET"){if(fileExists(filePath)){//文件存在std::string content = readFile(filePath);//讀取文件內容std::string contentType = getContentType(filePath);//獲取文件類型std::ostringstream response; // 構建響應response<<"HTTP/1.1 200 OK\r\n"<<"Content-Type:"<<contentType<<"\r\n"<<"Content-Length:"<<content.length()<<"\r\n"<<"\r\n"<<content;//響應頭和響應體response<<content;//發送響應send(new_socket, response.str().c_str(), response.str().length(), 0);}else{//404 NOT FOUNDstd::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請求//簡單的響應客戶端的POST請求(可以根據需要解析POST請求)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 ALLOWEDstd::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);}//關閉連接close(new_socket);}//釋放資源,關閉服務器套接字close(server_fd);return 0;
}
二、靜態文件結構
- 確保你的HTML、CSS、JS和圖片文件都存放在與可執行程序相同的目錄下或適當的子目錄中,例如:
./index.html
./style.css
./script.js
./images/example.jjpg
假設HTL文件是這樣的:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>這是一個簡單的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>這是一個簡單的WebServer</h1>
</header>
<main><p>這是一個簡單的WebServer,你可以在這里放置一些內容。</p><br/><img src="23.png" alt="C++測試">
</main>
<footer><p>©2025 My WebServer By HuJiaHang</p>
</footer></body>
</html>
三、編譯和運行
- 編譯
g++ -std=c++20 WebServer.cpp -o WebServer
//使用C++20標準,是因為std::string::ends_with()是C++20引入的功能
- 運行:執行編譯好的WebServer程序
./WebServer
四、訪問測試
- 使用瀏覽器訪問http://localhost:8080,可以獲取靜態HTML頁面、CSS樣式、JavaScript腳本和圖片
- 注意:如果使用的是云服務器,就必須要在安全組中放開端口
- 以下是我的測試