Skip to content

Commit 4199614

Browse files
committed
Add some github workflow
1 parent 6aa3e58 commit 4199614

File tree

2 files changed

+155
-6
lines changed

2 files changed

+155
-6
lines changed

.github/workflows/cmake.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CMake
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
env:
10+
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
11+
BUILD_TYPE: Release
12+
13+
jobs:
14+
build:
15+
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
16+
# You can convert this to a matrix build if you need cross-platform coverage.
17+
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- uses: actions/checkout@v2
22+
23+
- name: Configure CMake
24+
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
25+
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
26+
run: cmake -B ${{github.workspace}}/build -DIP_SOCKETS_CPP_LITE_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
27+
28+
- name: Build
29+
# Build your program with the given configuration
30+
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

readme.md

Lines changed: 125 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# ip-sockets-cpp-lite 🔌
22

3+
[![Build examples](https://github.com/biaks/ip-sockets-cpp-lite/actions/workflows/cmake.yml/badge.svg)](https://github.com/biaks/ip-sockets-cpp-lite/actions/workflows/cmake.yml)
4+
35
**Simplicity. Lightweight. Cross-platform.**
46

5-
ip-sockets-cpp-lite is a fast, header-only, dependency-free, cross-platform C++ library that makes programming UDP/TCP sockets and working with IPv4/IPv6 addresses as easy as possible.
7+
It's a fast, header-only, dependency-free, cross-platform C++ library that makes programming UDP/TCP sockets and working with IPv4/IPv6 addresses as easy as possible.
68
Forget about endless `getaddrinfo` calls, confusion with `sockaddr_in`/`sockaddr_in6`, and platform-specific workarounds.
79

810
```cpp
@@ -22,6 +24,74 @@ sock.send("Hello!", 6);
2224
- **🔒 Predictable** - full control over everything
2325
- **📋 Human-readable errors** - clear error codes instead of cryptic errno values
2426

27+
## Smart IP Address Handling 🌐
28+
29+
Working with IP addresses has never been easier:
30+
31+
### Create from anything
32+
```cpp
33+
// IPv4 addresses - all the common formats
34+
ip4_t ip0 = "192.168.1.1"; // from string
35+
ip4_t ip1 = 0xc0a80101; // from uint32
36+
ip4_t ip2 = {192, 168, 1, 1}; // from bytes
37+
ip4_t ip3 = "0xc0a80101"; // from hex string
38+
ip4_t ip4 = "3232235777"; // from decimal string
39+
ip4_t ip5 = "127.1"; // 127.0.0.1 (missing bytes are zero)
40+
// IPv6 addresses - all the common formats
41+
ip6_t ip6 = "fe80::"; // link-local address
42+
ip6_t ip7 = "::1"; // loopback
43+
ip6_t ip8 = "64:ff9b::10.0.0.7"; // IPv4-translated (NAT64)
44+
ip6_t ip9 = "11.0.0.1"; // auto IPv4-mapped to ::ffff:11.0.0.1
45+
// Parsing of all variants of input strings always occurs in one pass
46+
```
47+
48+
### Zero-copy overlay on existing memory
49+
```cpp
50+
uint8_t packet[14] = {0x45, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01, 0xa8, ...};
51+
// Treat memory region as ip4_t without copying!
52+
ip4_t& src_ip = *reinterpret_cast<ip4_t*>(&packet[3]);
53+
std::cout << src_ip; // prints "127.0.0.1"
54+
```
55+
56+
### Network operations made simple
57+
```cpp
58+
ip4_t ip = "192.168.1.100";
59+
ip4_t mask(24); // 255.255.255.0 from prefix
60+
ip4_t network = ip & mask; // 192.168.1.0
61+
62+
ip6_t ipv6 = "2001:db8::1";
63+
ip6_t ipv6_from_v4 = ip4_t("10.0.0.1"); // ::ffff:10.0.0.1 (IPv4-mapped)
64+
```
65+
66+
### Address + port as one type
67+
```cpp
68+
addr4_t server = "192.168.1.100:8080"; // IP and port together
69+
addr6_t server6 = "[2001:db8::1]:8080";
70+
std::cout << server; // prints "192.168.1.100:8080"
71+
```
72+
73+
### Two Ways to Use IP and Address Types 🔧
74+
```cpp
75+
// Direct types (when IP version is known)
76+
ip4_t ip4 = "192.168.1.1"; // IPv4
77+
ip6_t ip6 = "2001:db8::1"; // IPv6
78+
addr4_t addr4 = "192.168.1.1:8080"; // IPv4 + port
79+
addr6_t addr6 = "[::1]:8080"; // IPv6 + port
80+
81+
// Generic types (template-friendly)
82+
ip_t<v4> ip4 = "192.168.1.1"; // same as ip4_t
83+
ip_t<v6> ip6 = "2001:db8::1"; // same as ip6_t
84+
addr_t<v4> addr4 = "192.168.1.1:8080"; // same as addr4_t
85+
addr_t<v6> addr6 = "[::1]:8080"; // same as addr6_t
86+
87+
// Perfect for templates!
88+
template <ip_type_e Type>
89+
void print_endpoint(const addr_t<Type>& endpoint) {
90+
std::cout << "Connecting to: " << endpoint << '\n';
91+
}
92+
```
93+
**Choose what fits your code:** use concrete types for simplicity, or generic types for maximum flexibility in templates!
94+
2595
## Quick Start 🏁
2696
2797
### 1. Installation
@@ -31,7 +101,7 @@ Simply copy three files into your project:
31101
- `udp_socket.h` — UDP sockets
32102
- `tcp_socket.h` — TCP sockets
33103
34-
Then include one of what you need:
104+
Then include what you need:
35105
```cpp
36106
#include "ip_address.h" // work only with ipv4/ipv6 addresses
37107
#include "udp_socket.h" // work with UDP ipv4/ipv6 client/server sockets
@@ -78,7 +148,7 @@ int main() {
78148
// Create a UDP server on port 8080
79149
udp_socket_t<v4, socket_type_e::server> server;
80150

81-
if (server.open("0.0.0.0:8080") != no_error) {
151+
if (server.open("0.0.0.0:8080") == no_error) {
82152

83153
std::cout << "Server listening on port 8080\n";
84154

@@ -110,7 +180,7 @@ int main() {
110180
// Create a TCP server
111181
tcp_socket_t<v4, socket_type_e::server> server;
112182

113-
if (server.open("0.0.0.0:8080") != no_error) {
183+
if (server.open("0.0.0.0:8080") == no_error) {
114184

115185
std::cout << "TCP server listening on port 8080\n";
116186

@@ -138,7 +208,7 @@ int main() {
138208

139209
## Why is this convenient? 🤔
140210

141-
### Instead of this (raw sockets):
211+
Instead of this (system sockets):
142212
```cpp
143213
struct sockaddr_in addr;
144214
addr.sin_family = AF_INET;
@@ -147,12 +217,58 @@ inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
147217
// ... and 20 more lines to send a single packet
148218
```
149219
150-
### Write this:
220+
Just write this:
151221
```cpp
152222
sock.open("192.168.1.100:8080"); // done!
153223
sock.send("Hello", 5);
154224
```
155225

226+
## Synchronous with Timeouts — Why? ⏱️
227+
228+
You might wonder: "Why this library provide synchronous sockets with timeouts instead of async I/O?"
229+
230+
Great question! Here's why this design choice makes sense:
231+
232+
### ✅ Cross-platform simplicity
233+
Async I/O APIs differ dramatically between platforms (epoll on Linux, kqueue on BSD, IOCP on Windows).
234+
By choosing synchronous operations with timeouts, this library get a **single codebase** that works everywhere without #ifdef hell.
235+
236+
### ✅ Easy to understand and use
237+
No callbacks, no event loops, no complex state machines. Your code reads linearly:
238+
```cpp
239+
sock.open(server);
240+
sock.send(request);
241+
sock.recv(response); // blocks until data arrives or timeout
242+
```
243+
Every developer understands this flow instantly.
244+
245+
### ✅ Threads are cheap, complexity is expensive
246+
Spawning a thread to wait for socket I/O is perfectly fine:
247+
```cpp
248+
std::thread([&]() {
249+
while (true) {
250+
int bytes = server.recvfrom(buffer, sizeof(buffer), client);
251+
if (bytes > 0) handle_client(client, buffer, bytes);
252+
}
253+
}).detach(); // One thread per socket — no problem!
254+
```
255+
Modern systems handle thousands of threads easily. **Don't optimize prematurely** — clean code is better than complex async machinery.
256+
257+
### ✅ Perfect for 95% of use cases
258+
- REST API clients
259+
- IoT devices
260+
- Game servers
261+
- Protocol implementations
262+
- Embedded systems
263+
264+
For the 5% that truly need massive concurrency (10k+ connections), you can still use this library in thread pools or combine it with higher-level async frameworks.
265+
266+
---
267+
268+
**Bottom line:** This library gives you predictable, blocking I/O with configurable timeouts — the simplest model that works for most real-world applications. Keep it simple, keep it portable! 🎯
269+
270+
---
271+
156272
## Features 🔧
157273
158274
### IP Address Handling (`ip_address.h`)
@@ -161,6 +277,9 @@ sock.send("Hello", 5);
161277
- Network prefixes and masks
162278
- IPv4-over-IPv6 mapping
163279
- Address + port as a single unit
280+
- Zero-copy overlay on existing memory buffers
281+
- Rich constructors from strings, numbers, bytes
282+
- Flexible parsing of various formats (hex, decimal, dotted)
164283
165284
### UDP Sockets (`udp_socket.h`)
166285
- Client and server modes

0 commit comments

Comments
 (0)