Skip to content

Commit f927511

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

2 files changed

Lines changed: 216 additions & 49 deletions

File tree

.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: 186 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
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
9-
// Send a UDP packet? One line!
10-
udp_socket_t<v4, client> sock;
11-
sock.open("192.168.1.100:8080");
12-
sock.send("Hello!", 6);
11+
// Send a UDP packet to a hostname? No problem!
12+
udp_socket_t<v4, socket_type_e::client> sock (log_e::debug);
13+
ip4_t ip = sock.resolve("localhost", nullptr, log_e::debug);
14+
addr4_t addr = {ip, 8080};
15+
sock.open(addr);
16+
sock.send("Hello!", 6);
17+
18+
// Send a TCP message to an IPv6 address? Easy!
19+
tcp_socket_t<v6, socket_type_e::client> sock6 (log_e::debug);
20+
sock6.open("[::1]:8081");
21+
sock6.send("Hello!", 6);
22+
23+
//work with ip address from existing raw data with zero-copy? Okay
24+
uint8_t raw_data[10] = {0x45,0x00,0x00, 0x7f,0x00,0x00,0x01, 0xa8,0x00,0x00};
25+
ip4_t& reint_ip = *reinterpret_cast<ip4_t*>(&raw_data[3]);
26+
std::cout << "ip from raw data: " << reint_ip << std::endl;
27+
```
28+
29+
console output:
30+
```
31+
udp<ip4,client>: [static].resolve() [undefined -> localhost] DNS resolution success, resolved to '127.0.0.1'
32+
udp<ip4,client>: [3].open() [127.0.0.1:50902 <> 127.0.0.1:8080] success
33+
udp<ip4,client>: [3].send() [127.0.0.1:50902 -> 127.0.0.1:8080] sended 6 bytes
34+
tcp<ip6,client>: [4].open() [[::1]:39129 <> [::1]:8081] success
35+
tcp<ip6,client>: [4].send() [[::1]:39129 -> [::1]:8081] sended 6 bytes
36+
ip from raw data: 127.0.0.1
1337
```
1438
1539
## Why ip-sockets-cpp-lite? ✨
@@ -22,22 +46,125 @@ sock.send("Hello!", 6);
2246
- **🔒 Predictable** - full control over everything
2347
- **📋 Human-readable errors** - clear error codes instead of cryptic errno values
2448
49+
## Features 🔧
50+
51+
### IP Address Handling (`ip_address.h`)
52+
- Unified IPv4 and IPv6 support
53+
- String to binary and back conversion
54+
- Network prefixes and masks
55+
- IPv4-over-IPv6 mapping
56+
- Address + port as a single unit
57+
- Zero-copy overlay on existing memory buffers
58+
- Rich constructors from strings, numbers, bytes
59+
- Flexible parsing of various formats (hex, decimal, dotted)
60+
61+
### UDP Sockets (`udp_socket.h`)
62+
- Unified API and behavior across different OS
63+
- Client and server modes with IPv4 or IPv6 addresses
64+
- Blocking I/O with configurable timeouts
65+
- Сonfigurable comprehensive logging
66+
- Clear states and error codes across different OS
67+
68+
### TCP Sockets (`tcp_socket.h`)
69+
- Convenient accept with client socket creation
70+
- Automatic connection management
71+
- Consistent API with UDP sockets
72+
73+
## Requirements 📋
74+
- C++11 or newer
75+
- C++ standard library
76+
- Nothing else!
77+
2578
## Quick Start 🏁
2679
27-
### 1. Installation
80+
### 1. Project Integration 🛠️
2881
29-
Simply copy three files into your project:
82+
Option 1 — Simply copy header files what you need into your project:
3083
- `ip_address.h` — IP address handling
3184
- `udp_socket.h` — UDP sockets
3285
- `tcp_socket.h` — TCP sockets
3386
34-
Then include one of what you need:
87+
Option 2 — link library to your project via CMake
88+
```cmake
89+
add_subdirectory(ip-sockets-cpp-lite)
90+
target_link_libraries(your_app ip-sockets-cpp-lite)
91+
```
92+
93+
Then include what you need:
3594
```cpp
3695
#include "ip_address.h" // work only with ipv4/ipv6 addresses
3796
#include "udp_socket.h" // work with UDP ipv4/ipv6 client/server sockets
3897
#include "tcp_socket.h" // work with TCP ipv4/ipv6 client/server sockets
3998
```
4099

100+
### 2. Smart IP Address Handling 🌐
101+
102+
Working with IP addresses has never been easier:
103+
104+
#### Create from anything
105+
```cpp
106+
// IPv4 addresses - all the common formats
107+
ip4_t ip0 = "192.168.1.1"; // from string
108+
ip4_t ip1 = 0xc0a80101; // from uint32
109+
ip4_t ip2 = {192, 168, 1, 1}; // from bytes
110+
ip4_t ip3 = "0xc0a80101"; // from hex string
111+
ip4_t ip4 = "3232235777"; // from decimal string
112+
ip4_t ip5 = "127.1"; // 127.0.0.1 (missing bytes are zero)
113+
// IPv6 addresses - all the common formats
114+
ip6_t ip6 = "fe80::"; // link-local address
115+
ip6_t ip7 = "::1"; // loopback
116+
ip6_t ip8 = "64:ff9b::10.0.0.7"; // IPv4-translated (NAT64)
117+
ip6_t ip9 = "11.0.0.1"; // auto IPv4-mapped to ::ffff:11.0.0.1
118+
// Parsing of all variants of input strings always occurs in one pass
119+
```
120+
121+
#### Zero-copy overlay on existing memory
122+
```cpp
123+
uint8_t raw_data[10] = {0x45,0x00,0x00, 0x7f,0x00,0x00,0x01, 0xa8,0x00,0x00};
124+
// Treat memory region as ip4_t without copying!
125+
ip4_t& reint_ip = *reinterpret_cast<ip4_t*>(&raw_data[3]);
126+
std::cout << reint_ip << std::endl; // prints "127.0.0.1"
127+
```
128+
129+
#### Network operations made simple
130+
```cpp
131+
ip4_t ip = "192.168.1.100";
132+
ip4_t mask(24); // 255.255.255.0 from prefix
133+
ip4_t network = ip & mask; // 192.168.1.0
134+
135+
ip6_t ipv6 = "2001:db8::1";
136+
ip6_t ipv6_from_v4 = ip4_t("10.0.0.1"); // ::ffff:10.0.0.1 (IPv4-mapped)
137+
```
138+
139+
#### Address + port as one type
140+
```cpp
141+
addr4_t server = "192.168.1.100:8080"; // IP and port together
142+
addr6_t server6 = "[2001:db8::1]:8080";
143+
std::cout << server; // prints "192.168.1.100:8080"
144+
```
145+
146+
#### Two Ways to Use IP and Address Types 🔧
147+
```cpp
148+
// Direct types (when IP version is known)
149+
ip4_t ip4 = "192.168.1.1"; // IPv4
150+
ip6_t ip6 = "2001:db8::1"; // IPv6
151+
addr4_t addr4 = "192.168.1.1:8080"; // IPv4 + port
152+
addr6_t addr6 = "[::1]:8080"; // IPv6 + port
153+
154+
// Generic types (template-friendly)
155+
ip_t<v4> ip4 = "192.168.1.1"; // same as ip4_t
156+
ip_t<v6> ip6 = "2001:db8::1"; // same as ip6_t
157+
addr_t<v4> addr4 = "192.168.1.1:8080"; // same as addr4_t
158+
addr_t<v6> addr6 = "[::1]:8080"; // same as addr6_t
159+
160+
// Perfect for templates!
161+
template <ip_type_e Type>
162+
void print_endpoint(const addr_t<Type>& endpoint) {
163+
std::cout << "Connecting to: " << endpoint << '\n';
164+
}
165+
```
166+
**Choose what fits your code:** use concrete types for simplicity, or generic types for maximum flexibility in templates!
167+
41168
### 2. Send a UDP message
42169
43170
```cpp
@@ -78,7 +205,7 @@ int main() {
78205
// Create a UDP server on port 8080
79206
udp_socket_t<v4, socket_type_e::server> server;
80207

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

83210
std::cout << "Server listening on port 8080\n";
84211

@@ -110,7 +237,7 @@ int main() {
110237
// Create a TCP server
111238
tcp_socket_t<v4, socket_type_e::server> server;
112239

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

115242
std::cout << "TCP server listening on port 8080\n";
116243

@@ -136,70 +263,80 @@ int main() {
136263
}
137264
```
138265

266+
### 5. More examples 📚
267+
268+
Check out the `examples/` directory for complete working examples:
269+
- `ip_address.cpp` - all IP address manipulation features
270+
- `udp_socket.cpp` - UDP client-server interaction
271+
- `tcp_socket.cpp` - TCP client-server interaction
272+
- `resolve_host.cpp` - resolving host to ipv4/ipv6 address example
273+
139274
## Why is this convenient? 🤔
140275

141-
### Instead of this (raw sockets):
276+
Instead of this (system sockets):
142277
```cpp
278+
// ...
279+
// ifdef and include hell there for cross platform work
280+
// ...
143281
struct sockaddr_in addr;
144282
addr.sin_family = AF_INET;
145283
addr.sin_port = htons(8080);
146284
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
147285
// ... and 20 more lines to send a single packet
148286
```
149287
150-
### Write this:
288+
Just write this (this library):
151289
```cpp
290+
// single include and simple create socket object there
152291
sock.open("192.168.1.100:8080"); // done!
153292
sock.send("Hello", 5);
154293
```
155294

156-
## Features 🔧
295+
## Synchronous I/O with Timeouts — Why? ⏱️
157296

158-
### IP Address Handling (`ip_address.h`)
159-
- Unified IPv4 and IPv6 support
160-
- String to binary and back conversion
161-
- Network prefixes and masks
162-
- IPv4-over-IPv6 mapping
163-
- Address + port as a single unit
297+
You might wonder: "Why this library provide synchronous sockets with timeouts instead of async I/O?"
164298

165-
### UDP Sockets (`udp_socket.h`)
166-
- Client and server modes
167-
- Configurable timeouts
168-
- Polling-based asynchronous I/O
169-
- Clear states and error codes
299+
Great question! Here's why this design choice makes sense:
170300

171-
### TCP Sockets (`tcp_socket.h`)
172-
- Blocking I/O with timeouts
173-
- Convenient accept with client socket creation
174-
- Automatic connection management
175-
- Consistent API with UDP
301+
### ✅ Cross-platform simplicity
302+
Async I/O APIs differ dramatically between platforms (epoll on Linux, kqueue on BSD, IOCP on Windows).
303+
By choosing synchronous operations with timeouts, this library get a **single codebase** that works everywhere without #ifdef hell.
176304

177-
## Requirements 📋
305+
### ✅ Easy to understand and use
306+
No callbacks, no event loops, no complex state machines. Your code reads linearly:
307+
```cpp
308+
sock.open(server);
309+
sock.send(request);
310+
sock.recv(response); // blocks until data arrives or timeout
311+
```
312+
Every developer understands this flow instantly.
178313

179-
- C++11 or newer
180-
- C++ standard library
181-
- Nothing else!
314+
### ✅ Threads are cheap, complexity is expensive
315+
Spawning a thread to wait for socket I/O is perfectly fine:
316+
```cpp
317+
std::thread([&]() {
318+
while (true) {
319+
int bytes = server.recvfrom(buffer, sizeof(buffer), client);
320+
if (bytes > 0) handle_client(client, buffer, bytes);
321+
}
322+
}).detach(); // One thread per socket — no problem!
323+
```
324+
Modern systems handle thousands of threads easily. **Don't optimize prematurely** — clean code is better than complex async machinery.
182325
183-
## Project Integration 🛠️
326+
### ✅ Perfect for 95% of use cases
327+
- REST API clients
328+
- IoT devices
329+
- Game servers
330+
- Protocol implementations
331+
- Embedded systems
184332
185-
### Option 1 — Just copy the files
186-
```bash
187-
cp ip_address.h udp_socket.h tcp_socket.h /path/to/your/project/
188-
```
333+
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.
189334
190-
### Option 2 — CMake
191-
```cmake
192-
add_subdirectory(ip-sockets-cpp-lite)
193-
target_link_libraries(your_app ip-sockets-cpp-lite)
194-
```
335+
---
195336
196-
## Examples 📚
337+
**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! 🎯
197338
198-
Check out the `examples/` directory for complete working examples:
199-
- `ip_address.cpp` - all IP address manipulation features
200-
- `udp_socket.cpp` - UDP client-server interaction
201-
- `tcp_socket.cpp` - TCP client-server interaction
202-
- `resolve_host.cpp` - resolving host to ipv4/ipv6 address example
339+
---
203340
204341
## License 📄
205342

0 commit comments

Comments
 (0)