服务器实例
有个著名的项目,tiny web,本项目将其改到windows下,并使用RAII重构,编写过程中对于内存泄漏确实很头疼,还没写完,后面会继续更:
#include <iostream>
#include <vector>
#include <stdexcept>
#include <string>
#include<ranges>
#include<format>
#include <stdio.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "WS2_32.lib")
class WSAInitializer {
public:
WSAInitializer() {
WSADATA data;
int ret = WSAStartup(MAKEWORD(2, 2), &data);
if (ret != 0) {
throw std::runtime_error("WSAStartup failed. Error code: " + std::to_string(ret));
}
}
~WSAInitializer() {
WSACleanup();
}
WSAInitializer(const WSAInitializer&) = delete;
WSAInitializer& operator=(const WSAInitializer&) = delete;
};
class Socket {
public:
Socket() = default;
Socket(int domain, int type, int protocol) {
sock_ = socket(domain, type, protocol);
if (sock_ == INVALID_SOCKET) {
throw std::runtime_error("Socket creation failed. Error code: " + std::to_string(WSAGetLastError()));
}
}
explicit Socket(SOCKET s) : sock_(s) {}
~Socket() {
if (sock_ != INVALID_SOCKET) {
closesocket(sock_);
}
}
Socket(Socket&& other) noexcept : sock_(other.sock_) {
other.sock_ = INVALID_SOCKET;
}
Socket& operator=(Socket&& other) noexcept {
if (this != &other) {
closesocket(sock_);
sock_ = other.sock_;
other.sock_ = INVALID_SOCKET;
}
return *this;
}
SOCKET get() const { return sock_; }
operator SOCKET() const { return sock_; }
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
private:
SOCKET sock_ = INVALID_SOCKET;
};
Socket startup(unsigned short* port) {
Socket server_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int opt = 1;
if (setsockopt(server_socket.get(), SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&opt), sizeof(opt)) == SOCKET_ERROR) {
throw std::runtime_error("setsockopt failed. Error code: " + std::to_string(WSAGetLastError()));
}
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(*port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(server_socket.get(), reinterpret_cast<const sockaddr*>(&server_addr), sizeof(server_addr)) == SOCKET_ERROR) {
throw std::runtime_error("bind failed. Error code: " + std::to_string(WSAGetLastError()));
}
if (*port == 0) {
sockaddr_in name;
int nameLen = sizeof(name);
if (getsockname(server_socket.get(), reinterpret_cast<sockaddr*>(&name), &nameLen) == SOCKET_ERROR) {
throw std::runtime_error("getsockname failed. Error code: " + std::to_string(WSAGetLastError()));
}
*port = ntohs(name.sin_port);
}
if (listen(server_socket.get(), 5) == SOCKET_ERROR) {
throw std::runtime_error("listen failed. Error code: " + std::to_string(WSAGetLastError()));
}
return server_socket;
}
int get_line(SOCKET sock, std::vector<char>& buff, int size) {
buff.resize(size);
char c = 0;
int i = 0;
while (i < size - 1 && c != '\n') {
int n = recv(sock, &c, 1, 0);
if (n > 0) {
if (c == '\r') {
n = recv(sock, &c, 1, MSG_PEEK);
if (n > 0 && c == '\n') {
recv(sock, &c, 1, 0);
} else {
c = '\n';
}
}
buff[i++] = c;
} else {
c = '\n';
}
}
buff[i] = '\0';
return i;
}
void unimplemented(SOCKET client) {
const char* response = "HTTP/1.1 501 Not Implemented\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html><head><title>Not Implemented</title></head>"
"<body><h1>501 Not Implemented</h1></body></html>";
send(client, response, strlen(response), 0);
}
DWORD WINAPI accept_request(LPVOID arg) {
std::unique_ptr<Socket> client_socket(static_cast<Socket*>(arg));
SOCKET client = client_socket->get();
std::vector<char> buff(1024);
int numchars = get_line(client, buff, buff.size());
// 示例:解析请求方法
char method[255] = {0};
int i = 0, j = 0;
while (!isspace(buff[j]) && i < sizeof(method) - 1) {
method[i++] = buff[j++];
}
// 示例:检查支持的HTTP方法
if (_stricmp(method, "GET") && _stricmp(method, "POST")) {
unimplemented(client);
return 0;
}
// 示例:解析URL(简化版)
std::vector<char> url(255, 0);
i = 0;
while (isspace(buff[j]) && j < buff.size()) j++;
while (!isspace(buff[j]) && i < url.size() - 1 && j < buff.size()) {
url[i++] = buff[j++];
}
// 示例:发送响应(实际应处理请求)
const char* response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html><head><title>Test</title></head>"
"<body><h1>Hello World</h1></body></html>";
send(client, response, strlen(response), 0);
return 0;
}
int main() {
try {
WSAInitializer wsa;
unsigned short port = 8880;
Socket server_socket = startup(&port);
std::cout << "Server started on port " << port << std::endl;
while (true) {
sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
SOCKET client_sock = accept(server_socket.get(), reinterpret_cast<sockaddr*>(&client_addr), &addr_len);
if (client_sock == INVALID_SOCKET) {
throw std::runtime_error("accept failed. Error code: " + std::to_string(WSAGetLastError()));
}
Socket* client_socket = new Socket(client_sock);
HANDLE hThread = CreateThread(nullptr, 0, accept_request, client_socket, 0, nullptr);
if (!hThread) {
delete client_socket;
throw std::runtime_error("CreateThread failed. Error code: " + std::to_string(GetLastError()));
}
CloseHandle(hThread);
}
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}