Created
January 12, 2026 10:37
-
-
Save tabvn/71da7ba7378d08e03cce6c6426b2b92e to your computer and use it in GitHub Desktop.
http server in c++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * ====================================================================================== | |
| * HIGH-PERFORMANCE C++ HTTP & WEBSOCKET SERVER (Single File) | |
| * Supports: Linux (Epoll) & macOS (Kqueue) | |
| * Features: Non-blocking I/O, Event Loop, HTTP Routing, WebSocket Handshake & Frames | |
| * ====================================================================================== | |
| * | |
| * COMPILE INSTRUCTIONS: | |
| * --------------------- | |
| * Linux (Debian/Ubuntu): | |
| * sudo apt-get install libssl-dev | |
| * g++ -O3 -std=c++11 server.cpp -o server -lcrypto | |
| * | |
| * macOS: | |
| * clang++ -O3 -std=c++11 server.cpp -o server -lcrypto | |
| * | |
| * RUN: | |
| * ./server | |
| * ====================================================================================== | |
| */ | |
| #include <iostream> | |
| #include <string> | |
| #include <vector> | |
| #include <unordered_map> | |
| #include <functional> | |
| #include <sstream> | |
| #include <cstring> | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| #include <netinet/in.h> | |
| #include <sys/socket.h> | |
| #include <arpa/inet.h> | |
| #include <openssl/sha.h> | |
| #include <openssl/bio.h> | |
| #include <openssl/evp.h> | |
| #include <openssl/buffer.h> | |
| // --- PLATFORM DETECTION --- | |
| #if defined(__linux__) | |
| #include <sys/epoll.h> | |
| #define PLATFORM_LINUX | |
| #define ENGINE_NAME "Linux Epoll" | |
| #elif defined(__APPLE__) || defined(__FreeBSD__) | |
| #include <sys/event.h> | |
| #include <sys/time.h> | |
| #define PLATFORM_MAC | |
| #define ENGINE_NAME "macOS Kqueue" | |
| #else | |
| #error "Platform not supported. Use Linux or macOS." | |
| #endif | |
| #define MAX_EVENTS 10240 | |
| #define BUFFER_SIZE 8192 | |
| // ====================================================================================== | |
| // UTILITIES | |
| // ====================================================================================== | |
| static void set_non_blocking(int sockfd) { | |
| int flags = fcntl(sockfd, F_GETFL, 0); | |
| fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); | |
| } | |
| // Base64 Encode (OpenSSL) | |
| static std::string base64_encode(const unsigned char* input, int length) { | |
| BIO *bmem, *b64; | |
| BUF_MEM *bptr; | |
| b64 = BIO_new(BIO_f_base64()); | |
| bmem = BIO_new(BIO_s_mem()); | |
| b64 = BIO_push(b64, bmem); | |
| BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); | |
| BIO_write(b64, input, length); | |
| BIO_flush(b64); | |
| BIO_get_mem_ptr(b64, &bptr); | |
| std::string res(bptr->data, bptr->length); | |
| BIO_free_all(b64); | |
| return res; | |
| } | |
| // WebSocket Accept Key Generator (RFC 6455) | |
| static std::string generate_ws_accept(const std::string& key) { | |
| std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | |
| std::string combined = key + magic; | |
| unsigned char hash[SHA_DIGEST_LENGTH]; | |
| SHA1((unsigned char*)combined.c_str(), combined.length(), hash); | |
| return base64_encode(hash, SHA_DIGEST_LENGTH); | |
| } | |
| // ====================================================================================== | |
| // CONTEXT CLASSES | |
| // ====================================================================================== | |
| struct Request { | |
| std::string method; | |
| std::string path; | |
| std::unordered_map<std::string, std::string> headers; | |
| std::string body; | |
| }; | |
| // HTTP Context: Allows user to respond to HTTP requests | |
| class Context { | |
| public: | |
| int fd; | |
| Request req; | |
| bool is_closed = false; | |
| Context(int _fd, Request _req) : fd(_fd), req(_req) {} | |
| void send_raw(std::string status, std::string type, std::string body) { | |
| if (is_closed) return; | |
| std::string res = "HTTP/1.1 " + status + "\r\n" | |
| "Content-Type: " + type + "\r\n" | |
| "Content-Length: " + std::to_string(body.length()) + "\r\n" | |
| "Connection: close\r\n\r\n" + body; | |
| ::send(fd, res.c_str(), res.length(), 0); | |
| close(fd); | |
| is_closed = true; | |
| } | |
| void html(std::string body) { send_raw("200 OK", "text/html", body); } | |
| void json(std::string body) { send_raw("200 OK", "application/json", body); } | |
| void text(std::string body) { send_raw("200 OK", "text/plain", body); } | |
| }; | |
| // WebSocket Context: Allows user to send messages to connected WS clients | |
| class WSContext { | |
| public: | |
| int fd; | |
| WSContext(int _fd) : fd(_fd) {} | |
| void send(std::string msg) { | |
| // Construct WebSocket Frame (Text, Unmasked) | |
| unsigned char header[10]; | |
| size_t header_len = 2; | |
| header[0] = 0x81; // FIN + Text Opcode | |
| if (msg.length() <= 125) { | |
| header[1] = msg.length(); | |
| } else if (msg.length() <= 65535) { | |
| header[1] = 126; | |
| header[2] = (msg.length() >> 8) & 0xFF; | |
| header[3] = msg.length() & 0xFF; | |
| header_len = 4; | |
| } else { | |
| // Very large frames not handled in this basic demo | |
| header[1] = 127; | |
| } | |
| ::write(fd, header, header_len); | |
| ::write(fd, msg.c_str(), msg.length()); | |
| } | |
| }; | |
| // ====================================================================================== | |
| // FASTCORE FRAMEWORK (ENGINE) | |
| // ====================================================================================== | |
| class FastCore { | |
| using HttpHandler = std::function<void(Context&)>; | |
| using WSConnectHandler = std::function<void(WSContext&)>; | |
| using WSMessageHandler = std::function<void(WSContext&, std::string)>; | |
| struct Route { std::string method; HttpHandler handler; }; | |
| struct WSRoute { WSConnectHandler on_connect; WSMessageHandler on_message; }; | |
| // Storage for Routes | |
| std::unordered_map<std::string, Route> routes; | |
| std::unordered_map<std::string, WSRoute> ws_routes; | |
| // Track active WebSocket connections: FD -> Path | |
| std::unordered_map<int, std::string> active_ws_connections; | |
| public: | |
| // Define Routes | |
| void get(std::string path, HttpHandler handler) { routes["GET:" + path] = {"GET", handler}; } | |
| void post(std::string path, HttpHandler handler) { routes["POST:" + path] = {"POST", handler}; } | |
| void ws(std::string path, WSConnectHandler on_conn, WSMessageHandler on_msg) { ws_routes[path] = {on_conn, on_msg}; } | |
| // Start Server | |
| void run(int port) { | |
| int server_fd = setup_socket(port); | |
| std::cout << ">> FastCore Server Running on Port " << port << std::endl; | |
| std::cout << ">> Engine: " << ENGINE_NAME << std::endl; | |
| std::cout << ">> Waiting for connections..." << std::endl; | |
| #ifdef PLATFORM_LINUX | |
| run_epoll(server_fd); | |
| #else | |
| run_kqueue(server_fd); | |
| #endif | |
| } | |
| private: | |
| int setup_socket(int port) { | |
| int fd = socket(AF_INET, SOCK_STREAM, 0); | |
| int opt = 1; | |
| setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | |
| #ifdef PLATFORM_LINUX | |
| setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); | |
| #endif | |
| sockaddr_in addr; | |
| addr.sin_family = AF_INET; | |
| addr.sin_addr.s_addr = INADDR_ANY; | |
| addr.sin_port = htons(port); | |
| if (bind(fd, (sockaddr*)&addr, sizeof(addr)) < 0) { | |
| perror("Bind failed"); exit(1); | |
| } | |
| if (listen(fd, SOMAXCONN) < 0) { | |
| perror("Listen failed"); exit(1); | |
| } | |
| set_non_blocking(fd); | |
| return fd; | |
| } | |
| // --- LINUX EPOLL LOOP --- | |
| #ifdef PLATFORM_LINUX | |
| void run_epoll(int server_fd) { | |
| int epoll_fd = epoll_create1(0); | |
| struct epoll_event ev, events[MAX_EVENTS]; | |
| ev.events = EPOLLIN | EPOLLET; | |
| ev.data.fd = server_fd; | |
| epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev); | |
| while(true) { | |
| int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); | |
| for(int i = 0; i < nfds; ++i) { | |
| int fd = events[i].data.fd; | |
| if(fd == server_fd) { | |
| while(true) { | |
| sockaddr_in cli; socklen_t len = sizeof(cli); | |
| int conn = accept(server_fd, (sockaddr*)&cli, &len); | |
| if(conn < 0) break; | |
| set_non_blocking(conn); | |
| ev.events = EPOLLIN | EPOLLET; | |
| ev.data.fd = conn; | |
| epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn, &ev); | |
| } | |
| } else { | |
| handle_io(fd, [&](){ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL); }); | |
| } | |
| } | |
| } | |
| } | |
| #endif | |
| // --- MACOS KQUEUE LOOP --- | |
| #ifdef PLATFORM_MAC | |
| void run_kqueue(int server_fd) { | |
| int kq = kqueue(); | |
| struct kevent chg, events[MAX_EVENTS]; | |
| EV_SET(&chg, server_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); | |
| kevent(kq, &chg, 1, NULL, 0, NULL); | |
| while(true) { | |
| int nev = kevent(kq, NULL, 0, events, MAX_EVENTS, NULL); | |
| for(int i=0; i<nev; ++i) { | |
| if(events[i].flags & EV_EOF) { | |
| int fd = (int)events[i].ident; | |
| close(fd); | |
| active_ws_connections.erase(fd); | |
| continue; | |
| } | |
| int fd = (int)events[i].ident; | |
| if(fd == server_fd) { | |
| sockaddr_in cli; socklen_t len = sizeof(cli); | |
| int conn = accept(server_fd, (sockaddr*)&cli, &len); | |
| if(conn > 0) { | |
| set_non_blocking(conn); | |
| EV_SET(&chg, conn, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); | |
| kevent(kq, &chg, 1, NULL, 0, NULL); | |
| } | |
| } else { | |
| handle_io(fd, [](){}); | |
| } | |
| } | |
| } | |
| } | |
| #endif | |
| // --- SHARED I/O HANDLER --- | |
| void handle_io(int fd, std::function<void()> on_close_cleanup) { | |
| char buf[BUFFER_SIZE]; | |
| ssize_t bytes = read(fd, buf, BUFFER_SIZE); | |
| if (bytes <= 0) { | |
| close(fd); | |
| active_ws_connections.erase(fd); | |
| on_close_cleanup(); | |
| return; | |
| } | |
| // 1. Is this a known WebSocket connection? | |
| if (active_ws_connections.count(fd)) { | |
| std::string path = active_ws_connections[fd]; | |
| // Check for Text Frame (0x81) | |
| if ((unsigned char)buf[0] == 0x81) { | |
| unsigned char payload_len = buf[1] & 127; | |
| size_t offset = 2; | |
| if(payload_len == 126) offset = 4; | |
| else if(payload_len == 127) offset = 10; | |
| unsigned char mask[4]; | |
| memcpy(mask, buf + offset, 4); | |
| char* payload = buf + offset + 4; | |
| size_t data_len = bytes - (offset + 4); | |
| // Unmask the data | |
| for(size_t k=0; k<data_len; k++) payload[k] ^= mask[k%4]; | |
| std::string msg(payload, data_len); | |
| WSContext ws(fd); | |
| if (ws_routes.count(path)) ws_routes[path].on_message(ws, msg); | |
| } | |
| return; | |
| } | |
| // 2. Otherwise, treat as HTTP Request | |
| std::string raw(buf, bytes); | |
| Request req = parse_raw(raw); | |
| // Check for WebSocket Upgrade Header | |
| if (req.headers.count("Upgrade") && req.headers["Upgrade"] == "websocket") { | |
| if (ws_routes.count(req.path)) { | |
| std::string accept_key = generate_ws_accept(req.headers["Sec-WebSocket-Key"]); | |
| std::string res = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: websocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept: " + accept_key + "\r\n\r\n"; | |
| write(fd, res.c_str(), res.length()); | |
| // Register this FD as a WebSocket | |
| active_ws_connections[fd] = req.path; | |
| WSContext ws(fd); | |
| ws_routes[req.path].on_connect(ws); | |
| } else { | |
| close(fd); on_close_cleanup(); | |
| } | |
| } | |
| // Standard HTTP Route | |
| else { | |
| std::string routeKey = req.method + ":" + req.path; | |
| Context ctx(fd, req); | |
| if (routes.count(routeKey)) { | |
| routes[routeKey].handler(ctx); | |
| } else { | |
| ctx.send_raw("404 Not Found", "text/plain", "Route not found"); | |
| } | |
| } | |
| } | |
| Request parse_raw(const std::string& raw) { | |
| Request req; | |
| std::stringstream ss(raw); | |
| std::string line; | |
| // Parse Request Line | |
| std::getline(ss, line); | |
| if(!line.empty() && line.back() == '\r') line.pop_back(); | |
| std::stringstream first_line(line); | |
| first_line >> req.method >> req.path; | |
| // Parse Headers | |
| while(std::getline(ss, line) && line != "\r") { | |
| size_t colon = line.find(':'); | |
| if (colon != std::string::npos) { | |
| std::string key = line.substr(0, colon); | |
| std::string val = line.substr(colon + 2); | |
| if (!val.empty() && val.back() == '\r') val.pop_back(); | |
| req.headers[key] = val; | |
| } | |
| } | |
| return req; | |
| } | |
| }; | |
| // ====================================================================================== | |
| // USER APPLICATION LOGIC (MAIN) | |
| // ====================================================================================== | |
| int main() { | |
| FastCore app; | |
| // --- Route 1: Home Page --- | |
| app.get("/", [](Context& ctx) { | |
| std::string html = | |
| "<html><head><title>FastCore C++</title></head>" | |
| "<style>body{font-family:sans-serif; padding:2rem;}</style>" | |
| "<body>" | |
| "<h1>FastCore C++ Server</h1>" | |
| "<p>Status: <strong>Running</strong> | Engine: " ENGINE_NAME "</p>" | |
| "<hr>" | |
| "<h3>WebSocket Chat Demo</h3>" | |
| "<input id='msg' placeholder='Type message...'> " | |
| "<button onclick='send()'>Send</button>" | |
| "<div id='output' style='margin-top:20px; border:1px solid #ccc; padding:10px; height:200px; overflow:auto;'></div>" | |
| "<script>" | |
| " var ws = new WebSocket('ws://' + location.host + '/chat');" | |
| " ws.onopen = () => { log('Connected to server.'); };" | |
| " ws.onmessage = (e) => { log('Server: ' + e.data); };" | |
| " function send() { " | |
| " var m = document.getElementById('msg').value;" | |
| " ws.send(m); log('You: ' + m);" | |
| " }" | |
| " function log(s) { " | |
| " document.getElementById('output').innerHTML += s + '<br>';" | |
| " }" | |
| "</script>" | |
| "</body></html>"; | |
| ctx.html(html); | |
| }); | |
| // --- Route 2: JSON API --- | |
| app.get("/api/data", [](Context& ctx) { | |
| ctx.json("{\"id\": 101, \"message\": \"Hello from C++ JSON\"}"); | |
| }); | |
| // --- Route 3: WebSocket Chat --- | |
| app.ws("/chat", | |
| // On Connect | |
| [](WSContext& ws) { | |
| std::cout << "[WS] New Client Connected" << std::endl; | |
| ws.send("Welcome to the C++ Realtime Core!"); | |
| }, | |
| // On Message | |
| [](WSContext& ws, std::string msg) { | |
| std::cout << "[WS] Received: " << msg << std::endl; | |
| // Echo back reversed or normal | |
| if (msg == "ping") ws.send("pong"); | |
| else ws.send("Echo: " + msg); | |
| } | |
| ); | |
| // Run on Port 8080 | |
| app.run(8080); | |
| return 0; | |
| } | |
| // Linux: sudo apt-get install libssl-dev && g++ -O3 main.cpp -o server -lcrypto | |
| // Macos: clang++ -std=c++11 main.cpp -o server -lcrypto | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment