-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from kassane/cpp-serverClient
Add C++ HTTP server and client
- Loading branch information
Showing
7 changed files
with
258 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
const std = @import("std"); | ||
|
||
pub fn build(b: *std.Build) void { | ||
const target = b.standardTargetOptions(.{}); | ||
const optimize = b.standardOptimizeOption(.{}); | ||
|
||
const libasio_dep = b.dependency("asio", .{ | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
const libasio = libasio_dep.artifact("asio"); | ||
|
||
const exe = b.addExecutable(.{ | ||
.name = "cpp-asio-httpclient", | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
// get include to zig-cache/i/{hash-pkg}/include | ||
for (libasio.include_dirs.items) |include| { | ||
exe.include_dirs.append(include) catch {}; | ||
} | ||
exe.addCSourceFile(.{ | ||
.file = .{ | ||
.path = "src/main.cpp", | ||
}, | ||
.flags = &.{ | ||
"-Wall", | ||
"-Wextra", | ||
"-Wshadow", | ||
}, | ||
}); | ||
exe.linkLibrary(libasio); | ||
exe.linkLibCpp(); | ||
|
||
b.installArtifact(exe); | ||
|
||
const run_cmd = b.addRunArtifact(exe); | ||
run_cmd.step.dependOn(b.getInstallStep()); | ||
|
||
if (b.args) |args| { | ||
run_cmd.addArgs(args); | ||
} | ||
|
||
const run_step = b.step("run", "Run the app"); | ||
run_step.dependOn(&run_cmd.step); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.{ | ||
.name = "cpp-asio-httpclient", | ||
.version = "0.1.0", | ||
.license = "MIT", | ||
.dependencies = .{ | ||
.asio = .{ | ||
.url = "https://github.com/kassane/asio/archive/2e97b6a4d37be85529d191380eeda67240fd61fe.tar.gz", | ||
.hash = "12208b60f54e758b964ad3038973b7c4198d40ed6d6ea2955b6e44cee971e6edeb5e", | ||
}, | ||
}, | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
#include <asio.hpp> | ||
#include <chrono> | ||
#include <iostream> | ||
#include <memory> | ||
#include <thread> | ||
#include <vector> | ||
|
||
using asio::ip::tcp; | ||
|
||
class HttpClient { | ||
public: | ||
HttpClient(asio::io_context &ioContext) | ||
: ioContext_(ioContext), socket_(ioContext) {} | ||
|
||
void connect(const std::string &host, const std::string &port) { | ||
tcp::resolver resolver(ioContext_); | ||
endpoints_ = resolver.resolve(host, port); | ||
asio::connect(socket_, endpoints_); | ||
} | ||
|
||
void sendRequest(const std::string &request, | ||
std::function<void(const std::string &)> onResponse) { | ||
onResponse_ = std::move(onResponse); | ||
asio::async_write(socket_, asio::buffer(request), | ||
[this](std::error_code ec, std::size_t /*length*/) { | ||
if (!ec) { | ||
readResponse(); | ||
} else { | ||
std::cerr << "Write error: " << ec.message() | ||
<< std::endl; | ||
} | ||
}); | ||
} | ||
|
||
void readResponse() { | ||
asio::async_read_until(socket_, responseBuffer_, "\r\n\r\n", | ||
[this](std::error_code ec, std::size_t /*length*/) { | ||
if (!ec) { | ||
processResponse(); | ||
} else { | ||
std::cerr << "Read error: " << ec.message() | ||
<< std::endl; | ||
} | ||
}); | ||
} | ||
|
||
void processResponse() { | ||
std::istream responseStream(&responseBuffer_); | ||
|
||
std::string header; | ||
while (std::getline(responseStream, header) && header != "\r") { | ||
std::cout << header << std::endl; | ||
} | ||
|
||
std::ostringstream contentStream; | ||
if (responseBuffer_.size() > 0) { | ||
contentStream << &responseBuffer_; | ||
onResponse_(contentStream.str()); | ||
} | ||
|
||
socket_.close(); | ||
} | ||
|
||
private: | ||
asio::io_context &ioContext_; | ||
tcp::socket socket_; | ||
tcp::resolver::results_type endpoints_; | ||
asio::streambuf responseBuffer_; | ||
std::function<void(const std::string &)> onResponse_; | ||
}; | ||
|
||
int main() { | ||
try { | ||
asio::io_context ioContext; | ||
|
||
const std::string host = "localhost"; | ||
const std::string port = "8000"; | ||
|
||
std::vector<std::unique_ptr<HttpClient>> clients; | ||
std::vector<std::string> responses; | ||
|
||
for (int i = 0; i < 1000; ++i) { | ||
clients.emplace_back(std::make_unique<HttpClient>(ioContext)); | ||
clients.back()->connect(host, port); | ||
clients.back()->sendRequest( | ||
"GET /get HTTP/1.1\r\n" | ||
"Host: localhost\r\n" | ||
"Connection: close\r\n" | ||
"\r\n", | ||
[&](const std::string &response) { responses.push_back(response); }); | ||
} | ||
|
||
ioContext.run(); | ||
|
||
// Process responses as needed | ||
for (const auto &response : responses) { | ||
std::cout << "Response Content: " << response << std::endl; | ||
} | ||
} catch (const std::exception &e) { | ||
std::cerr << "Error: " << e.what() << std::endl; | ||
} | ||
|
||
return 0; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const std = @import("std"); | ||
|
||
pub fn build(b: *std.Build) void { | ||
const target = b.standardTargetOptions(.{}); | ||
const optimize = b.standardOptimizeOption(.{}); | ||
|
||
// Standalone-Server uses asio (standalone/non-boost) | ||
const libasio_dep = b.dependency("standaloneServer", .{ | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
const libasio = libasio_dep.artifact("Standalone-server"); | ||
|
||
const exe = b.addExecutable(.{ | ||
.name = "cpp-asio-httpserver", | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
// get include to zig-cache/i/{hash-pkg}/include | ||
for (libasio.include_dirs.items) |include| { | ||
exe.include_dirs.append(include) catch {}; | ||
} | ||
exe.addCSourceFile(.{ | ||
.file = .{ | ||
.path = "src/main.cpp", | ||
}, | ||
.flags = &.{ | ||
"-Wall", | ||
"-Wextra", | ||
"-Wshadow", | ||
}, | ||
}); | ||
// use standalone asio - non-boost | ||
exe.defineCMacro("ASIO_STANDALONE", null); | ||
exe.linkLibrary(libasio); | ||
exe.linkLibCpp(); | ||
|
||
b.installArtifact(exe); | ||
|
||
const run_cmd = b.addRunArtifact(exe); | ||
run_cmd.step.dependOn(b.getInstallStep()); | ||
|
||
if (b.args) |args| { | ||
run_cmd.addArgs(args); | ||
} | ||
|
||
const run_step = b.step("run", b.fmt("Run the {s} app", .{exe.name})); | ||
run_step.dependOn(&run_cmd.step); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.{ | ||
.name = "cpp-asio-httpserver", | ||
.version = "0.1.0", | ||
.license = "MIT", | ||
.dependencies = .{ | ||
.standaloneServer = .{ | ||
.url = "https://github.com/kassane/Standalone-Server/archive/12af18dfce121f5c6dc59702a0bbf99ce69f1677.tar.gz", | ||
.hash = "1220b0320efd82e58de88d8a7ea86777efd39cb6196b2a4abdcdf3e264707121770e", | ||
}, | ||
}, | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#include <iostream> | ||
#include <string> | ||
#include <server_http.hpp> | ||
|
||
using HttpServer = SimpleWeb::Server<SimpleWeb::HTTP>; | ||
|
||
int main() { | ||
// Create the HTTP server | ||
HttpServer server; | ||
server.config.port = 8000; | ||
|
||
// Define the request handler | ||
server.resource["^/get$"]["GET"] = [](std::shared_ptr<HttpServer::Response> response, std::shared_ptr<HttpServer::Request> request) { | ||
std::string content = "C++ Bits!\n"; | ||
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; | ||
}; | ||
|
||
// Start the server | ||
std::cout << "Server started on port 8000." << std::endl; | ||
server.start(); | ||
|
||
return 0; | ||
} |