1. Introduction
In embedded AI application development, we often need to add HTTP network interfaces to devices for remote control, data upload, or information queries.
Traditional methods often require introducing complex dependency libraries, which can be cumbersome.
In practical development, I prefer using a single header file solution, such as cpp-httplib, which is a single-header C++ HTTP library that allows your project to quickly and easily have HTTP server and client capabilities.
In addition to powerful HTTP capabilities, cpp-httplib also provides useful non-HTTP components, such as thread pools and utility classes, which are also very useful in embedded AI development.
2. What is cpp-httplib
cpp-httplib is an open-source C++11 library that consists of a single header file (httplib.h) but provides complete HTTP server and client functionality. Its features include:
- • Zero dependencies: Only include one header file, no need to install other libraries
- • Cross-platform: Supports Linux, Windows, macOS, etc.
- • Simple and easy to use: Intuitive API design, low learning cost
- • Comprehensive functionality: Supports HTTPS, file uploads, multipart forms, etc.
3. Quick Start
3.1 Download the Header File
First, download the httplib.h header file from the GitHub repository:
wget https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h
3.2 Example HTTP Server Program
3.2.1 Prepare Example Source Code
Here is a simple HTTP server example:
#include "httplib.h"
#include <iostream>
int main() {
httplib::Server svr;
svr.Get("/hello", [](const httplib::Request& req, httplib::Response& res) {
res.set_content("Hello World!\n\n", "text/plain");
});
svr.Post("/predict", [](const httplib::Request& req, httplib::Response& res) {
std::string result = "Received: " + req.body + "\n\n";
res.set_content(result, "text/plain");
});
std::cout << "Server starting on http://localhost:8080" << std::endl;
// Listening returns false indicates an error
if (!svr.listen("0.0.0.0", 8080)) {
std::cerr << "Failed to start server on port 8080. Maybe the port is already in use?" << std::endl;
return -1;
}
return 0;
}
3.2.2 Compile and Run
Save the above code as main.cpp in a Linux environment, placing it in the same directory as httplib.h, compile and run:
# Create a development directory, e.g., httpTest
mkdir httpTest
cd httpTest
# Place the above two files httplib.h and main.cpp in this directory
# Compile to generate the executable file httpServer
g++ -std=c++11 main.cpp -o httpServer -lpthread
# Run httpServer
chmod +x httpServer
./httpServer
You may encounter port occupation issues, as shown in the figure below:

In this case, you need to modify the source code to use an unoccupied port number, such as 38080.
# Check if 38080 is occupied
netstat -tulpn | grep :38080
After modifying the port number in the source code to 38080, compile and run, you can see the program in a blocking listen state:

3.2.3 Use Tools to Test the Server Example Program
The above server example program provides two HTTP interfaces: the /hello endpoint with the GET method, and the /predict endpoint with the POST method. We can use existing HTTP client tools to test and verify.
Common tools on Windows include Postman, while in Linux environments, we can use the curl command. Here we will demonstrate using curl.Open another terminal and enter:
# Verify hello interface
curl http://localhost:38080/hello
# Verify predict interface
curl -X POST -d '{"data": "test"}' http://localhost:38080/predict
You can see the returned messages, both interfaces verified OK:

3.3 Create an HTTP Client
At the same time, you can easily create an HTTP client, which is very simple, so we won’t compile and test it:
#include "httplib.h"
#include <iostream>
int main() {
// Create HTTP client
httplib::Client cli("http://localhost:8080");
// Send GET request
if (auto res = cli.Get("/hello")) {
std::cout << "Response status: " << res->status << std::endl;
std::cout << "Response content: " << res->body << std::endl;
} else {
std::cout << "Request failed: " << res.error() << std::endl;
}
// Send POST request (for AI inference)
std::string json_data = "{\"input\": \"test data\"}";
if (auto res = cli.Post("/predict", json_data, "application/json")) {
std::cout << "AI inference result: " << res->body << std::endl;
}
return 0;
}
4. Practical Functional Components Provided by cpp-httplib
4.1 Thread Pool
cpp-httplib internally implements an efficient thread pool, mainly used for handling concurrent HTTP requests.However, this thread pool is designed to be general enough that we can also use it directly in our own projects. Here is an example code:
#include "httplib.h"
#include <iostream>
#include <chrono>
int main() {
// Create thread pool, default number of threads is the current hardware concurrency
httplib::ThreadPool pool;
// Or specify the number of threads
// httplib::ThreadPool pool(4); // 4 threads
// Submit tasks to the thread pool
auto future1 = pool.enqueue([]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return "Task 1 completed";
});
auto future2 = pool.enqueue([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return "Task 2 completed";
});
// Get task results
std::cout << future2.get() << std::endl; // First completed task
std::cout << future1.get() << std::endl; // Later completed task
return 0;
}
4.2 File Service
cpp-httplib has built-in static file service functionality:
int main() {
httplib::Server svr;
// Provide static file service
svr.set_base_dir("./www");
// Custom file download
svr.Get("/download/model", [](const httplib::Request& req, httplib::Response& res) {
// Set file download header
res.set_header("Content-Disposition", "attachment; filename=model.bin");
// Read and send model file
std::ifstream file("model.bin", std::ios::binary);
if (file) {
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
res.set_content(content, "application/octet-stream");
}
});
svr.listen("0.0.0.0", 8080);
return 0;
}
4.3 HTTPS Support
Enabling HTTPS is also very simple:
int main() {
// Enable HTTPS
httplib::SSLServer svr("./server.crt", "./server.key");
svr.Get("/secure", [](const httplib::Request& req, httplib::Response& res) {
res.set_content("Secure connection", "text/plain");
});
svr.listen("0.0.0.0", 8443);
return 0;
}
4.4 String Processing Utilities
cpp-httplib provides a series of string processing functions, example application code:
#include "httplib.h"
void string_utils_example() {
std::string str = "Hello World";
// String conversion
std::string lower = httplib::detail::to_lower(str);
std::string upper = httplib::detail::to_upper(str);
// String trimming
std::string padded = " hello ";
std::string trimmed = httplib::detail::trim(padded);
// String splitting
std::string csv = "apple,banana,orange";
auto parts = httplib::detail::split(csv, ',');
// URL encoding/decoding
std::string url_encoded = httplib::detail::encode_url("hello world&test");
std::string url_decoded = httplib::detail::decode_url("hello%20world%26test");
// Base64 encoding/decoding
std::string base64_encoded = httplib::detail::base64_encode("hello world");
std::string base64_decoded = httplib::detail::base64_decode("aGVsbG8gd29ybGQ=");
std::cout << "Lower: " << lower << std::endl;
std::cout << "Trimmed: '" << trimmed << "'" << std::endl;
std::cout << "Parts count: " << parts.size() << std::endl;
}
4.5 File System Utilities
#include "httplib.h"
void filesystem_examples() {
// Check if file exists
bool exists = httplib::detail::exists("test.txt");
// Read file content
std::string content = httplib::detail::read_file("test.txt");
// Write to file
httplib::detail::write_file("output.txt", "Hello File");
// Get file size
size_t size = httplib::detail::get_file_size("test.txt");
// Scan directory (requires enabling filesystem support)
#ifdef CPPHTTPLIB_USE_STD_FILESYSTEM
auto files = httplib::detail::list_files(".");
for (const auto& file : files) {
std::cout << file << std::endl;
}
#endif
}
4.6 Network Utilities
#include "httplib.h"
void network_utils_example() {
// Get local IP address
std::string host = httplib::detail::get_host_name();
// Check if port is occupied
bool port_used = httplib::detail::is_port_available(8080);
std::cout << "Host: " << host << std::endl;
std::cout << "Port 8080 available: " << (port_used ? "No" : "Yes") << std::endl;
}
4.7 Date and Time Utilities
#include "httplib.h"
void datetime_examples() {
// Get current time string (HTTP date format)
std::string http_date = httplib::detail::get_header_value(
nullptr, httplib::detail::make_http_date_header()
);
// Get timestamp
auto now = std::chrono::system_clock::now();
std::time_t timestamp = std::chrono::system_clock::to_time_t(now);
std::cout << "HTTP Date: " << http_date << std::endl;
std::cout << "Timestamp: " << timestamp << std::endl;
}
5. Applications in Embedded AI Projects
5.1 Scenario 1: Model as a Service
Expose the trained AI model through HTTP interfaces for easy access by other systems:
// AI model service example
class AIModel {
public:
std::string predict(const std::string& input) {
// Implement model inference logic here
return "Prediction result";
}
};
int main() {
AIModel model;
httplib::Server svr;
// Model inference interface
svr.Post("/model/predict", [&model](const httplib::Request& req, httplib::Response& res) {
try {
std::string result = model.predict(req.body);
res.set_content(result, "application/json");
} catch (const std::exception& e) {
res.status = 500;
res.set_content(e.what(), "text/plain");
}
});
// Model information interface
svr.Get("/model/info", [&model](const httplib::Request& req, httplib::Response& res) {
nlohmann::json info = {
{"model_name", "resnet18"},
{"version", "1.0"},
{"input_shape", "224x224x3"}
};
res.set_content(info.dump(), "application/json");
});
svr.listen("0.0.0.0", 8080);
return 0;
}
5.2 Scenario 2: Device Status Monitoring
Add status monitoring interfaces for embedded devices:
// Device status service
class DeviceMonitor {
private:
float cpu_temperature = 45.6f;
int memory_usage = 65;
public:
nlohmann::json get_status() {
return {
{"cpu_temperature", cpu_temperature},
{"memory_usage", memory_usage},
{"model_inference_count", 1234},
{"status", "normal"}
};
}
};
int main() {
DeviceMonitor monitor;
httplib::Server svr;
// Device status query
svr.Get("/status", [&monitor](auto& req, auto& res) {
auto status = monitor.get_status();
res.set_content(status.dump(), "application/json");
});
// Health check
svr.Get("/health", [](auto& req, auto& res) {
res.set_content("OK", "text/plain");
});
svr.listen("0.0.0.0", 8080);
return 0;
}
6. Performance Considerations
In embedded environments, performance is key. cpp-httplib performs excellently in this regard:
- • Low memory usage: Single-header design, small size after compilation
- • Concurrent processing: Supports multi-threaded request handling
- • Resource-friendly: Buffer size and thread count can be adjusted as needed
// Performance optimization configuration example
int main() {
httplib::Server svr;
// Set read timeout
svr.set_read_timeout(5, 0); // 5 seconds
// Set write timeout
svr.set_write_timeout(5, 0); // 5 seconds
// Limit request body size (to prevent memory overflow)
svr.set_payload_max_length(1024 * 1024); // 1MB
// Register routes
svr.Get("/ai/predict", [](auto& req, auto& res) {
// AI inference processing
});
svr.listen("0.0.0.0", 8080);
return 0;
}
7. Conclusion
cpp-httplib provides an extremely convenient HTTP solution for C++ developers, especially for embedded AI developers. Its single-header design makes integration very simple, and its powerful features can meet most network communication needs.Main advantages include:
- • Zero dependencies, single header file
- • Quick integration, can be up and running in minutes
- • Complete HTTP server and client functionality
- • Suitable for resource-constrained embedded environments
- • Active open-source community support