10 ms·
Show HN: BinaryRPC – Lightweight WebSocket-based RPC framework in modern C++
Hi HN,
I’m a recent CS graduate.
During the past few months I wrote BinaryRPC, an open-source RPC framework in modern C++20 focused on low-latency, binary WebSocket messaging.
Why I built it
* Wanted first-class session support, pluggable QoS levels and a simple middleware chain (global, specific, multi handler) without extra JSON/XML parsing.
* Easy developer experience
A quick feature list
* Binary WebSocket frames – minimal overhead
* Built-in session layer (login / reconnect / heartbeat)
* QoS1 / QoS2 with automatic ACK & retry
* Plugin system – rooms, msgpack, etc. can be added in one line
* Thread-safe core: RAII + folly
Still early (solo project), so any feedback on design, concurrency model or missing must-have features would help a lot.
Thanks for reading!
also see "Chat Server in 5 Minutes with BinaryRPC": https://medium.com/@efecanerdem0907/building-a-chat-server-in-5-minutes-with-binaryrpc-qos2-session-management-and-room-plugin-ccb66d722466 https://medium.com/@efecanerdem0907/building-a-chat-server-i...
- gr4vityWall 1y agoCongrats on your project. Did you get to replace the old Java prototype you were using at work? It'd be interesting to see how the performance compares.
- efecan0 1y agoWe did move the service from the old Java / STOMP prototype to a BinaryRPC stack earlier this quarter, but I’m still gathering formal benchmark data before I publish anything public. Informally, on the same hardware and traffic pattern we see: • noticeable CPU head-room • lower p95 latency • higher peak throughput Once I have a full week of numbers cleaned up, I’ll add a short performance section to the README and post the graphs. Thanks for the interest stay tuned.
- jayd16 1y agoMy immediate reaction is why websocket based design and TCP (?) over gRPC with http/3 and UDP and multiplexing and such?
- efecan0 1y agoI started with WebSocket over TCP for practical reasons: * Works everywhere today (browsers, LB, PaaS) with zero extra setup. * One upgrade -> binary frames; no gRPC/proto toolchain or HTTP/3 infra needed. * Simple reliability: TCP handles ordering; I add optional QoS2 on top. * Lets me focus on session/room/middleware features first; transport is swappable later. QUIC / gRPC-HTTP/3 is on the roadmap once the higher-level API stabilises.
- seangrogg 1y agoAssuming you're locked in on the browser WebSockets are about as good as it gets at present. HTTP/3 requires WebTransport which has been a bit of a shitshow in terms of getting things up and running so far, in my experience.
- efecan0 1y agoThanks, that matches my experience as well. For browser clients WebSocket is still ‘the path of least pain’, so I’m keeping it as the default. When WebTransport and QUIC become easier to deploy I’ll add an optional transport module. If you’ve tried any recent WebTransport builds and have tips or docs, I’d love to see them—feel free to open an issue or drop a link. Appreciate the confirmation!
- inetknght 1y agoI'm not the author but off the top of my head: - gRPC is not a library I would trust with safety or privacy. It's used a lot but isn't a great product. I have personally found several fuckups in gRPC and protobuf code resulting in application crashes or risks of remote code execution. Their release tagging is dogshit, their implementation makes you think the standard library and boost libraries are easy to read and understand, and neither takes SDLC lifecycles seriously since there aren't sanitizer builds nor fuzzing regime nor static analysis running against new commits last time I checked. - http/3 using UDP sends performance into the crater, generally requiring _every_ packet to reach the CPU in userspace instead of being handled in the kernel or even directly by the network interface hardware - multiplexing isn't needed by most websocket applications
- efecan0 1y agoHi everyone, thanks for checking out BinaryRPC! I built this project because I needed a simple but fast WebSocket-based RPC layer for my own real-time side projects. Existing options felt heavy or JSON-only, so I wrote something binary-focused and plugin-friendly. I’d really appreciate any feedback on: • Overall architecture / design smells • Concurrency model (thread-pool vs async IO) • “Must-have” features before this is production-ready Design notes and a 5-minute chat-server demo are in this short post: https://medium.com/@efecanerdem0907/building-a-chat-server-in-5-minutes-with-binaryrpc-qos2-session-management-and-room-plugin-ccb66d722466 https://medium.com/@efecanerdem0907/building-a-chat-server-i... Any comments, suggestions or PRs are welcome. Thanks again!
- deleted 1y ago[deleted]
- jeffbee 1y agoBreezy claims of "exactly once" are a red flag for me. Aside from that I think this framework looks fairly promising.
- efecan0 1y agoGood catch—let me clarify what QoS 2 in BinaryRPC really does. It follows the MQTT-style 2-step handshake: 1. Sender → `PUBLISH(id, data)` 2. Receiver → `PUBREC(id)` // stored as “seen but not completed” 3. Sender → `PUBREL(id)` 4. Receiver → `PUBCOMP(id)` // marks id as done, then passes data to the app layer While an id is in “seen” state the receiver drops duplicates, so the message is delivered to user code exactly once per session even if the socket retries. If the client reconnects with the same session-key, the server reloads the in-flight id table, so duplicates are still filtered. If the session is lost (no session-key) we fall back to at-least-once because there is no common store. So: “exactly once within a persisted session; effectively once” as long as the application is idempotent. I’ll update the docs to state this more precisely. Thanks for pointing it out!
- denizdoktur 1y agoLightweight, well-designed, and solves a real need. Impressive.
- efecan0 1y agoThanks!
- sahinemirhan 1y agoVery good
- dailker 1y agonice I loved it dude. I hope you get succesful on this.
- MuffinFlavored 1y ago> None, AtLeastOnce, ExactlyOnce with retries, ACKs & two‑phase commit, plus pluggable back‑off strategies & per‑session TTL. Sounds like RabbitMQ/AMQP/similar over WebSocket?
- efecan0 1y agoIt looks similar on the surface, but scope and goals are different: * BinaryRPC = direct request/response calls with optional QoS (per session). – No exchanges/queues, no routing keys. – One logical stream, messages mapped to handlers. * RabbitMQ / AMQP = full message-broker with persistent queues, fan-out, topic routing, etc. So you could say BinaryRPC covers the transport/QoS part of AMQP, but stays lightweight and broker-less. If an app later needs full queueing we can still bridge to AMQP, but the core idea here is “RPC first, minimal deps”.
- sarpistan 1y agoGood job
- sph87 1y agoModules my guy. The words “modern” and “C++” don’t go together while using headers. Also your most basic implementation requires me to write 200+ LOC and add a dozen headers. Then it’s a ton of boiler plate code duplication for every function registered. Basically what I am saying is - you need to place more abstraction between your code and the end-user API. Take this line: std::string sayMessage = payload["message"].template get<std::string>(); Why not make a templated getString<“message”> that pulls from payload? So that would instead just be: auto sayMessage = payload[“message”].as_string() or auto sayMessage = payload.getString<“message”>() or std::string sayMessage = payload[“message”] //We infer type from the assignment!! It’s way cleaner. Way more effective. Way more intuitive. When working on this kind of stuff end-developer experience should always drive the process. Look at your JSON library. Well known and loved. Imagine if instead of: message[“code”] = “JOIN”; it was instead something like: message.template set<std::string, std::string>(“CODE”, “JOIN”); Somehow I don’t think the latter would have seen any level of meaningful adoption. It’s weird, obtuse and overly complex. You need to hide all that.
- efecan0 1y agoHi. Thank you for the detailed feedback—this is exactly the kind of input that helps the project grow. You’re right: developer experience needs to be better. Right now there is too much boiler-plate and not enough abstraction. Your example std::string msg = payload["message"]; // type inferred is the direction I want to take. I’ll add a thin wrapper so users can write `payload["key"].as_string()` or even rely on assignment type-inference. Refactoring the basic chat demo to be much shorter is now my next task. About C++20 modules: I agree they are the future. The single-header client was a quick MVP, but module support is on the roadmap as compiler tooling matures. If you have more DX ideas or want to discuss API design, please open an issue on GitHub I’d be happy to collaborate. Thanks again for the valuable feedback!
- const_cast 1y agoOn the topic of modules: a single-header template implementation is still the most practical and quick way to distribute a library. Module support is currently iffy - I wouldn't use them.
- jpc0 1y ago> uwebsockets zlib boost folly glog gflags fmt double-conversion openssl usockets Lightweight is a little bit of an exaggeration. What is the reason for using boost::thread over std::thread for this? I haven’t had time to dig through the code but most of the time I’ve found it was for compatibility with older compilers but you explicitly require C++20 support. Regarding deps why not just standardise on vcpkg, it’s already a requirement for windows. That way you can use a manifest and ensure your dependencies are always the same version. Better yet I would try to strip some of the more annoying to build libraries (cough folly) and replace them with more “standard” libraries that you can include using CPM and drop the requirement for vcpkg completely.
- efecan0 1y agoHi, author here (new-grad, v0.1.0 is literally the first public cut) – thanks a lot for the detailed dependency review! So the real hard deps should end up as: `uWebSockets + usockets + OpenSSL + fmt` Everything else will be opt-in. Road-map update (just added): 1. Merge `std::thread` rewrite (dev branch) 2. Remove folly/double-conversion, glog/gflags 3. Provide single-header client & minimal build script 4. Add `vcpkg.json` for Windows; Linux/macOS stay pure CMake/FetchContent Your feedback is shaping v0.2.0 – please keep it coming! Feel free to open a Discussion or issue if you spot more low-hanging DX wins. Really appreciate the help
- lipovna 1y agoWow, its a very good project
- efecan0 1y agoThank you all for the incredible feedback and thoughtful critique. It genuinely helped shape the direction of the project. I've just published a detailed Road Map (https://github.com/efecan0/binaryrpc-framework/blob/main/RoadMap.md https://github.com/efecan0/binaryrpc-framework/blob/main/Roa...) based on the discussions here. It includes core cleanup (bye bye Folly, hello absl), a modular transport layer, and better ergonomics for real-world apps. This was my first open-source release and seeing it hit #1 on HN was surreal. I appreciate everyone who took the time to comment. If you're interested in helping shape the project further, feel free to join the discussion or file issues. Thanks again — Efecan