#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>
#include <map>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <sys/stat.h>
#include <direct.h>
#include <locale>
#include <ctime>
#include <stdexcept>
#include <windows.h>
#include <tchar.h>
#include <cstdio>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
// 全局变量
HWND hWnd, hLogEdit, hStatusStatic, hStartButton, hStopButton, hFontCombo, hSizeCombo;
HANDLE hServerThread = NULL;
bool g_isServerRunning = false;
CRITICAL_SECTION logCriticalSection;
int g_winsockRefCount = 0;
// 字体相关
int g_fontSize = 20;
HFONT g_hFont = NULL;
const int MIN_FONT_SIZE = 12, MAX_FONT_SIZE = 24;
TCHAR g_currentFont[64] = _T("Consolas");
const TCHAR *fontList[] = { _T("微软雅黑"), _T("宋体"), _T("黑体"), _T("楷体"), _T("隶书"), _T("Consolas"), _T("Arial"), _T("SimSun"), _T("SimHei"), _T("KaiTi") };
const int fontCount = sizeof(fontList) / sizeof(fontList[0]);
// 服务器核心类前置声明
class WebServer;
// 日志管理器类
class LogManager {
private:
string logDir, sysLogFile, netLogFile;
HWND hLogWnd;
void ensureLogDirectory() {
struct stat info;
if (stat(logDir.c_str(), &info) != 0) {
if (_mkdir(logDir.c_str()) != 0)
throw runtime_error("无法创建日志目录: " + logDir);
} else if (!(info.st_mode & S_IFDIR))
throw runtime_error(logDir + " 不是一个目录");
}
public:
LogManager(const string &dir = "log", HWND logWnd = NULL) : logDir(dir), hLogWnd(logWnd),
sysLogFile(dir + "\\sys.log"), netLogFile(dir + "\\net.log") {
ensureLogDirectory();
}
string getTimestamp() {
time_t now = time(nullptr);
tm localTime;
localtime_s(&localTime, &now);
char buffer[80];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &localTime);
return "[" + string(buffer) + "] ";
}
void writeSystemLog(const string &message) {
string logEntry = getTimestamp() + message;
ofstream(logEntry, ios::app) << logEntry << endl;
addToLog("系统: " + logEntry);
}
void writeNetworkLog(const string &message) {
string logEntry = getTimestamp() + message;
ofstream(netLogFile, ios::app) << logEntry << endl;
addToLog("网络: " + logEntry);
}
void addToLog(const string &message) {
if (!hLogWnd)
return;
EnterCriticalSection(&logCriticalSection);
int length = GetWindowTextLength(hLogWnd);
SendMessage(hLogWnd, EM_SETSEL, length, length);
SendMessage(hLogWnd, EM_REPLACESEL, FALSE, (LPARAM)(message + "\r\n").c_str());
SendMessage(hLogWnd, WM_VSCROLL, SB_BOTTOM, 0);
LeaveCriticalSection(&logCriticalSection);
}
};
// 配置管理器类
class ConfigManager {
private:
map<string, string> configs;
string configFile;
void parseLine(const string &line) {
size_t commentPos = line.find('#'), start = line.find_first_not_of(" \t");
if (start == string::npos)
return;
string lineContent = (commentPos != string::npos) ? line.substr(0, commentPos) : line;
lineContent = lineContent.substr(start, lineContent.find_last_not_of(" \t") - start + 1);
size_t spacePos = lineContent.find_first_of(" \t");
if (spacePos == string::npos)
return;
string key = lineContent.substr(0, spacePos);
size_t valueStart = lineContent.find_first_not_of(" \t", spacePos);
if (valueStart != string::npos)
configs[key] = lineContent.substr(valueStart);
}
void logError(const string &message) {
cerr << "[错误] " << message << endl;
EnterCriticalSection(&logCriticalSection);
int length = GetWindowTextLength(hLogEdit);
SendMessage(hLogEdit, EM_SETSEL, length, length);
SendMessage(hLogEdit, EM_REPLACESEL, FALSE, (LPARAM)(("[错误] " + message + "\r\n").c_str()));
SendMessage(hLogEdit, WM_VSCROLL, SB_BOTTOM, 0);
LeaveCriticalSection(&logCriticalSection);
}
void checkRequiredConfigs() {
vector<string> required = {"listen", "default"};
for (const string &key : required)
if (configs.find(key) == configs.end() || configs[key].empty())
logError("配置文件缺少必要项: " + key);
try {
stoi(configs["listen"]);
} catch (...) {
logError("配置项listen必须是有效的端口号");
}
}
public:
ConfigManager(const string &file = "config.txt") : configFile(file) {
configs["root"] = "page";
configs["404page"] = "404.html";
configs["charset"] = "UTF-8";
ifstream cfgFile(configFile);
if (cfgFile.is_open()) {
string line;
while (getline(cfgFile, line))
parseLine(line);
} else
logError("未找到配置文件: " + configFile);
checkRequiredConfigs();
}
string getString(const string &key) {
return configs.count(key) ? configs[key] : "";
}
int getInt(const string &key) {
try {
return configs.count(key) ? stoi(configs[key]) : 0;
} catch (...) {
return 0;
}
}
};
// Web服务器类(双栈支持)
class WebServer {
private:
int port;
string rootDir, defaultPage, error404, charset;
SOCKET ipv4Socket, ipv6Socket;
LogManager &logger;
bool isRunning;
thread ipv4Thread, ipv6Thread;
string urlDecode(const string &encoded) {
string decoded;
for (size_t i = 0; i < encoded.size(); i++) {
if
自己做的web服务器软件(只有最普通的功能)
于 2025-08-21 13:03:48 首次发布