Random Port Generator — C++ source
Generate one or many random TCP/UDP port numbers across registered, ephemeral, or the full range - optionally unique. Runs entirely in your browser with crypto-grade randomness.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// random-port-generator — C++ port: random/dynamic port picker.
//
// Display port of the CosmoDev Random Port Generator tool — same contract as
// cli/random-port-generator/random-port-generator.go (the live Go twin) and
// src/lib/random-port.ts (the canonical TypeScript implementation). The
// default rng draws from std::random_device — the system entropy source —
// through std::uniform_real_distribution (display-grade randomness like the
// other C-family ports). An injectable rng keeps generation deterministic
// (the TS test surface); invalid custom ranges throw std::invalid_argument,
// mirroring the TS throw.
#include <algorithm>
#include <cmath>
#include <functional>
#include <iostream>
#include <map>
#include <random>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
enum class PortRange { Any, Registered, Ephemeral, Custom };
/// PortOptions in the TS lib (count/unique cover randomPorts). min/max of 0
/// mean unset, falling back to the full-range defaults like
/// resolveRange({range:'custom'}) in the TS lib.
struct PortOptions {
PortRange range = PortRange::Registered; // the TS default (registered ports)
int min = 0; // custom-range lower bound
int max = 0; // custom-range upper bound
int count = 1; // how many ports (randomPorts)
bool unique = false; // dedupe (randomPorts)
std::function<double()> rng; // injectable random in [0, 1); empty = default
};
namespace {
const std::map<PortRange, std::pair<int, int>> kRanges = {
{PortRange::Any, {1, 65535}},
{PortRange::Registered, {1024, 49151}},
{PortRange::Ephemeral, {49152, 65535}},
};
/// defaultRng() in the TS lib: one draw in [0, 1) from the system entropy source.
double defaultRng() {
static std::mt19937_64 engine{std::random_device{}()};
return std::uniform_real_distribution<double>(0.0, 1.0)(engine);
}
} // namespace
/// resolveRange() in the TS lib.
std::pair<int, int> resolveRange(const PortOptions& opts) {
if (opts.range == PortRange::Custom) {
return {opts.min ? opts.min : 1, opts.max ? opts.max : 65535};
}
return kRanges.at(opts.range);
}
/// assertRange() in the TS lib — the TS Error becomes an exception.
void assertRange(int lo, int hi) {
if (lo < 0 || lo > 65535 || hi > 65535 || lo > hi) {
throw std::invalid_argument("Invalid port range " + std::to_string(lo) + "-" + std::to_string(hi));
}
}
/// randomPort() in the TS lib — Port() in the Go twin.
int randomPort(const PortOptions& opts) {
auto rng = opts.rng ? opts.rng : defaultRng;
auto [lo, hi] = resolveRange(opts);
assertRange(lo, hi);
return lo + static_cast<int>(std::floor(rng() * (hi - lo + 1)));
}
/// randomPorts() in the TS lib — Ports() in the Go twin.
std::vector<int> randomPorts(const PortOptions& opts) {
const int count = std::max(1, opts.count);
auto [lo, hi] = resolveRange(opts);
assertRange(lo, hi);
if (!opts.unique) {
std::vector<int> out;
out.reserve(count);
for (int i = 0; i < count; i++) out.push_back(randomPort(opts));
return out;
}
// Fisher-Yates partial shuffle over the range to pick n unique ports.
const int capacity = hi - lo + 1;
const int n = std::min(count, capacity);
auto rng = opts.rng ? opts.rng : defaultRng;
std::vector<int> pool(capacity);
for (int i = 0; i < capacity; i++) pool[i] = lo + i;
for (int i = 0; i < n; i++) {
int j = i + static_cast<int>(std::floor(rng() * (capacity - i)));
std::swap(pool[i], pool[j]);
}
pool.resize(n);
return pool;
}
int main() {
// Vectors from src/lib/random-port.test.ts — a fixed rng pins every draw.
auto zero = [] { return 0.0; };
std::cout << "registered+0 = " << randomPort({.rng = zero}) << '\n'; // 1024
std::cout << "any+0 = " << randomPort({.range = PortRange::Any, .rng = zero}) << '\n'; // 1
std::cout << "ephemeral+0 = " << randomPort({.range = PortRange::Ephemeral, .rng = zero}) << '\n'; // 49152
std::cout << "custom 8000-8000 @0.9 = "
<< randomPort({.range = PortRange::Custom, .min = 8000, .max = 8000, .rng = [] { return 0.9; }})
<< '\n'; // 8000
auto d = resolveRange({.range = PortRange::Custom});
std::cout << "resolveRange(custom defaults) = " << d.first << ".." << d.second << '\n'; // 1..65535
for (const auto& [label, ports] : std::vector<std::pair<const char*, std::vector<int>>>{
{"count=5 @0", randomPorts({.count = 5, .rng = zero})}, // [1024 x5]
{"unique 3 in 1..10 @0.5",
randomPorts({.count = 3, .unique = true, .range = PortRange::Custom,
.min = 1, .max = 10, .rng = [] { return 0.5; }})}, // [6, 1, 7]
{"unique 5 in 1..3 @0.5",
randomPorts({.count = 5, .unique = true, .range = PortRange::Custom,
.min = 1, .max = 3, .rng = [] { return 0.5; }})}, // capped at capacity 3
}) {
std::cout << label << " = [";
for (size_t i = 0; i < ports.size(); i++) std::cout << (i ? ", " : "") << ports[i];
std::cout << "]\n";
}
int p = randomPort({}); // default rng, registered range
std::cout << "default rng registered = " << p << " (in 1024..49151)\n";
for (const auto& bad : std::vector<PortOptions>{
{.range = PortRange::Custom, .min = 70000}, // min above 65535
{.range = PortRange::Custom, .min = 100, .max = 50}, // min above max
}) {
try {
randomPort(bad);
} catch (const std::invalid_argument& e) {
std::cout << "invalid: " << e.what() << '\n';
}
}
return 0;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →