Skip to content

Commit 4e466bf

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

File tree

2 files changed

+217
-50
lines changed

2 files changed

+217
-50
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: 187 additions & 50 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,131 @@ sock.send("Hello!", 6);
2246
- **🔒 Predictable** - full control over everything
2347
- **📋 Human-readable errors** - clear error codes instead of cryptic errno values
2448
49+
---
50+
51+
This header only library gives you predictable, cross platform blocking I/O udp and tcp sockets with configurable timeouts — the simplest model that works for most real-world applications. Keep it simple, keep it portable! 🎯
52+
53+
---
54+
55+
## Features 🔧
56+
57+
### IP Address Handling (`ip_address.h`)
58+
- Unified IPv4 and IPv6 support
59+
- String to binary and back conversion
60+
- Network prefixes and masks
61+
- IPv4-over-IPv6 mapping
62+
- Address + port as a single unit
63+
- Zero-copy overlay on existing memory buffers
64+
- Rich constructors from strings, numbers, bytes
65+
- Flexible parsing of various formats (hex, decimal, dotted)
66+
67+
### UDP Sockets (`udp_socket.h`)
68+
- Unified API and behavior across different OS
69+
- Client and server modes with IPv4 or IPv6 addresses
70+
- Blocking I/O with configurable timeouts
71+
- Сonfigurable comprehensive logging
72+
- Clear states and error codes across different OS
73+
74+
### TCP Sockets (`tcp_socket.h`)
75+
- Convenient accept with client socket creation
76+
- Automatic connection management
77+
- Consistent API with UDP sockets
78+
79+
## Requirements 📋
80+
- C++11 or newer
81+
- C++ standard library
82+
- Nothing else!
83+
2584
## Quick Start 🏁
2685
27-
### 1. Installation
86+
### 1. Project Integration 🛠️
2887
29-
Simply copy three files into your project:
88+
Option 1 — Simply copy header files what you need into your project:
3089
- `ip_address.h` — IP address handling
3190
- `udp_socket.h` — UDP sockets
3291
- `tcp_socket.h` — TCP sockets
3392
34-
Then include one of what you need:
93+
Option 2 — link library to your project via CMake
94+
```cmake
95+
add_subdirectory(ip-sockets-cpp-lite)
96+
target_link_libraries(your_app ip-sockets-cpp-lite)
97+
```
98+
99+
Then include what you need:
35100
```cpp
36101
#include "ip_address.h" // work only with ipv4/ipv6 addresses
37102
#include "udp_socket.h" // work with UDP ipv4/ipv6 client/server sockets
38103
#include "tcp_socket.h" // work with TCP ipv4/ipv6 client/server sockets
39104
```
40105

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

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

83216
std::cout << "Server listening on port 8080\n";
84217

@@ -110,7 +243,7 @@ int main() {
110243
// Create a TCP server
111244
tcp_socket_t<v4, socket_type_e::server> server;
112245

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

115248
std::cout << "TCP server listening on port 8080\n";
116249

@@ -136,70 +269,74 @@ int main() {
136269
}
137270
```
138271

272+
### 5. More examples 📚
273+
274+
Check out the `examples/` directory for complete working examples:
275+
- `ip_address.cpp` - all IP address manipulation features
276+
- `udp_socket.cpp` - UDP client-server interaction
277+
- `tcp_socket.cpp` - TCP client-server interaction
278+
- `resolve_host.cpp` - resolving host to ipv4/ipv6 address example
279+
139280
## Why is this convenient? 🤔
140281

141-
### Instead of this (raw sockets):
282+
Instead of this (system sockets):
142283
```cpp
284+
// ...
285+
// ifdef and include hell there for cross platform work
286+
// ...
143287
struct sockaddr_in addr;
144288
addr.sin_family = AF_INET;
145289
addr.sin_port = htons(8080);
146290
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
147291
// ... and 20 more lines to send a single packet
148292
```
149293
150-
### Write this:
294+
Just write this (this library):
151295
```cpp
296+
// single include and simple create socket object there
152297
sock.open("192.168.1.100:8080"); // done!
153298
sock.send("Hello", 5);
154299
```
155300

156-
## Features 🔧
157-
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
164-
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
301+
## Synchronous I/O with Timeouts — Why? ⏱️
170302

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
303+
You might wonder: "Why this library provide synchronous sockets with timeouts instead of async I/O?"
176304

177-
## Requirements 📋
178-
179-
- C++11 or newer
180-
- C++ standard library
181-
- Nothing else!
305+
Great question! Here's why this design choice makes sense:
182306

183-
## Project Integration 🛠️
307+
### ✅ Cross-platform simplicity
308+
Async I/O APIs differ dramatically between platforms (epoll on Linux, kqueue on BSD, IOCP on Windows).
309+
By choosing synchronous operations with timeouts, this library get a **single codebase** that works everywhere without #ifdef hell.
184310

185-
### Option 1 — Just copy the files
186-
```bash
187-
cp ip_address.h udp_socket.h tcp_socket.h /path/to/your/project/
311+
### ✅ Easy to understand and use
312+
No callbacks, no event loops, no complex state machines. Your code reads linearly:
313+
```cpp
314+
sock.open(server);
315+
sock.send(request);
316+
sock.recv(response); // blocks until data arrives or timeout
188317
```
318+
Every developer understands this flow instantly.
189319

190-
### Option 2 — CMake
191-
```cmake
192-
add_subdirectory(ip-sockets-cpp-lite)
193-
target_link_libraries(your_app ip-sockets-cpp-lite)
320+
### ✅ Threads are cheap, complexity is expensive
321+
Spawning a thread to wait for socket I/O is perfectly fine:
322+
```cpp
323+
std::thread([&]() {
324+
while (true) {
325+
int bytes = server.recvfrom(buffer, sizeof(buffer), client);
326+
if (bytes > 0) handle_client(client, buffer, bytes);
327+
}
328+
}).detach(); // One thread per socket — no problem!
194329
```
330+
Modern systems handle thousands of threads easily. **Don't optimize prematurely** — clean code is better than complex async machinery.
195331
196-
## Examples 📚
332+
### ✅ Perfect for 95% of use cases
333+
- REST API clients
334+
- IoT devices
335+
- Game servers
336+
- Protocol implementations
337+
- Embedded systems
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+
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.
203340
204341
## License 📄
205342

0 commit comments

Comments
 (0)