Skip to content

Commit b0237f2

Browse files
Add UDP echo example (#65)
Fix #64 --------- Co-authored-by: Jiacai Liu <dev@liujiacai.net>
1 parent 2b1e08b commit b0237f2

File tree

5 files changed

+85
-1
lines changed

5 files changed

+85
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
book
22
zig-out/
33
zig-cache/
4+
.zig-cache/
45
.DS_Store
56
.tool-versions

book-src/04-03-udp-echo.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## UDP Echo
2+
3+
Similar to the TCP server example, this program will listen on the specified
4+
IP address and port, but for UDP datagrams this time. If data is received,
5+
it will be echoed back to the sender's address.
6+
7+
Although `std.net` is mostly focused on abstractions for TCP (so far), we can still
8+
make use of socket programming to communicate via UDP.
9+
10+
```zig
11+
{{#include ../src/04-03.zig }}
12+
```
13+
14+
After starting the program, test as follows with `nc`, using the `-u` flag for UDP:
15+
16+
```bash
17+
echo "hello zig" | nc -u localhost <port>
18+
```

book-src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
- [Listen on unused port TCP/IP](./04-01-tcp-server.md)
2323
- [TCP Client](./04-02-tcp-client.md)
24+
- [UDP Echo](./04-03-udp-echo.md)
2425

2526
- [Web Programming]()
2627

build.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ fn addExample(b: *std.Build, run_all: *std.Build.Step) !void {
7171

7272
// 04-01 start tcp server, and won't stop so we skip it here
7373
// 04-02 is the server's client.
74-
if (std.mem.eql(u8, "04-01", name) or std.mem.eql(u8, "04-02", name)) {
74+
// 04-03 starts udp listener.
75+
if (std.mem.eql(u8, "04-01", name) or
76+
std.mem.eql(u8, "04-02", name) or
77+
std.mem.eql(u8, "04-03", name))
78+
{
7579
continue;
7680
}
7781
run_all.dependOn(run_step);

src/04-03.zig

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! Start a UDP echo on an unused port.
2+
//!
3+
//! Test with
4+
//! echo "hello zig" | nc -u localhost <port>
5+
6+
const std = @import("std");
7+
const net = std.net;
8+
const posix = std.posix;
9+
const print = std.debug.print;
10+
11+
pub fn main() !void {
12+
// adjust the ip/port here as needed
13+
const addr = try net.Address.parseIp("127.0.0.1", 32100);
14+
15+
// get a socket and set domain, type and protocol flags
16+
const sock = try posix.socket(
17+
posix.AF.INET,
18+
posix.SOCK.DGRAM,
19+
posix.IPPROTO.UDP,
20+
);
21+
22+
// for completeness, we defer closing the socket. In practice, if this is
23+
// a one-shot program, we could omit this and let the OS do the cleanup
24+
defer posix.close(sock);
25+
26+
try posix.bind(sock, &addr.any, addr.getOsSockLen());
27+
28+
var other_addr: posix.sockaddr = undefined;
29+
var other_addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
30+
31+
var buf: [1024]u8 = undefined;
32+
33+
print("Listen on {any}...\n", .{addr});
34+
35+
// we did not set the NONBLOCK flag (socket type flag),
36+
// so the program will wait until data is received
37+
const n_recv = try posix.recvfrom(
38+
sock,
39+
buf[0..],
40+
0,
41+
&other_addr,
42+
&other_addrlen,
43+
);
44+
print(
45+
"received {d} byte(s) from {any};\n string: {s}\n",
46+
.{ n_recv, other_addr, buf[0..n_recv] },
47+
);
48+
49+
// we could extract the source address of the received data by
50+
// parsing the other_addr.data field
51+
52+
const n_sent = try posix.sendto(
53+
sock,
54+
buf[0..n_recv],
55+
0,
56+
&other_addr,
57+
other_addrlen,
58+
);
59+
print("echoed {d} byte(s) back\n", .{n_sent});
60+
}

0 commit comments

Comments
 (0)