comparison third_party/libuv/docs/src/guide/networking.rst @ 160:948de3f54cea

[ThirdParty] Added libuv
author June Park <parkjune1995@gmail.com>
date Wed, 14 Jan 2026 19:39:52 -0800
parents
children
comparison
equal deleted inserted replaced
159:05cf9467a1c3 160:948de3f54cea
1 Networking
2 ==========
3
4 Networking in libuv is not much different from directly using the BSD socket
5 interface, some things are easier, all are non-blocking, but the concepts stay
6 the same. In addition libuv offers utility functions to abstract the annoying,
7 repetitive and low-level tasks like setting up sockets using the BSD socket
8 structures, DNS lookup, and tweaking various socket parameters.
9
10 The ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O.
11
12 .. NOTE::
13
14 The code samples in this chapter exist to show certain libuv APIs. They are
15 not examples of good quality code. They leak memory and don't always close
16 connections properly.
17
18 TCP
19 ---
20
21 TCP is a connection oriented, stream protocol and is therefore based on the
22 libuv streams infrastructure.
23
24 Server
25 ++++++
26
27 Server sockets proceed by:
28
29 1. ``uv_tcp_init`` the TCP handle.
30 2. ``uv_tcp_bind`` it.
31 3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new
32 connection is established by a client.
33 4. Use ``uv_accept`` to accept the connection.
34 5. Use :ref:`stream operations <buffers-and-streams>` to communicate with the
35 client.
36
37 Here is a simple echo server
38
39 .. rubric:: tcp-echo-server/main.c - The listen socket
40 .. literalinclude:: ../../code/tcp-echo-server/main.c
41 :language: c
42 :linenos:
43 :lines: 68-
44 :emphasize-lines: 4-5,7-10
45
46 You can see the utility function ``uv_ip4_addr`` being used to convert from
47 a human readable IP address, port pair to the sockaddr_in structure required by
48 the BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``.
49
50 .. NOTE::
51
52 There are ``uv_ip6_*`` analogues for the ip4 functions.
53
54 Most of the setup functions are synchronous since they are CPU-bound.
55 ``uv_listen`` is where we return to libuv's callback style. The second
56 arguments is the backlog queue -- the maximum length of queued connections.
57
58 When a connection is initiated by clients, the callback is required to set up
59 a handle for the client socket and associate the handle using ``uv_accept``.
60 In this case we also establish interest in reading from this stream.
61
62 .. rubric:: tcp-echo-server/main.c - Accepting the client
63 .. literalinclude:: ../../code/tcp-echo-server/main.c
64 :language: c
65 :linenos:
66 :lines: 51-66
67 :emphasize-lines: 9-10
68
69 The remaining set of functions is very similar to the streams example and can
70 be found in the code. Just remember to call ``uv_close`` when the socket isn't
71 required. This can be done even in the ``uv_listen`` callback if you are not
72 interested in accepting the connection.
73
74 Client
75 ++++++
76
77 Where you do bind/listen/accept on the server, on the client side it's simply
78 a matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style
79 callback of ``uv_listen`` is used by ``uv_tcp_connect``. Try::
80
81 uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
82 uv_tcp_init(loop, socket);
83
84 uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t));
85
86 struct sockaddr_in dest;
87 uv_ip4_addr("127.0.0.1", 80, &dest);
88
89 uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect);
90
91 where ``on_connect`` will be called after the connection is established. The
92 callback receives the ``uv_connect_t`` struct, which has a member ``.handle``
93 pointing to the socket.
94
95 UDP
96 ---
97
98 The `User Datagram Protocol`_ offers connectionless, unreliable network
99 communication. Hence libuv doesn't offer a stream. Instead libuv provides
100 non-blocking UDP support via the `uv_udp_t` handle (for receiving) and
101 `uv_udp_send_t` request (for sending) and related functions. That said, the
102 actual API for reading/writing is very similar to normal stream reads. To look
103 at how UDP can be used, the example shows the first stage of obtaining an IP
104 address from a `DHCP`_ server -- DHCP Discover.
105
106 .. note::
107
108 You will have to run `udp-dhcp` as **root** since it uses well known port
109 numbers below 1024.
110
111 .. rubric:: udp-dhcp/main.c - Setup and send UDP packets
112 .. literalinclude:: ../../code/udp-dhcp/main.c
113 :language: c
114 :linenos:
115 :lines: 7-11,104-
116 :emphasize-lines: 8,10-11,17-18,21
117
118 .. note::
119
120 The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP
121 address ``255.255.255.255`` is a broadcast address meaning that packets
122 will be sent to all interfaces on the subnet. port ``0`` means that the OS
123 randomly assigns a port.
124
125 First we setup the receiving socket to bind on all interfaces on port 68 (DHCP
126 client) and start a read on it. This will read back responses from any DHCP
127 server that replies. We use the UV_UDP_REUSEADDR flag to play nice with any
128 other system DHCP clients that are running on this computer on the same port.
129 Then we setup a similar send socket and use ``uv_udp_send`` to send
130 a *broadcast message* on port 67 (DHCP server).
131
132 It is **necessary** to set the broadcast flag, otherwise you will get an
133 ``EACCES`` error [#]_. The exact message being sent is not relevant to this
134 book and you can study the code if you are interested. As usual the read and
135 write callbacks will receive a status code of < 0 if something went wrong.
136
137 Since UDP sockets are not connected to a particular peer, the read callback
138 receives an extra parameter about the sender of the packet.
139
140 ``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL,
141 it indicates there is nothing to read (the callback shouldn't do anything), if
142 not NULL, it indicates that an empty datagram was received from the host at
143 ``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer
144 provided by your allocator was not large enough to hold the data. *In this case
145 the OS will discard the data that could not fit* (That's UDP for you!).
146
147 .. rubric:: udp-dhcp/main.c - Reading packets
148 .. literalinclude:: ../../code/udp-dhcp/main.c
149 :language: c
150 :linenos:
151 :lines: 17-40
152 :emphasize-lines: 1,23
153
154 UDP Options
155 +++++++++++
156
157 Time-to-live
158 ~~~~~~~~~~~~
159
160 The TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``.
161
162 IPv6 stack only
163 ~~~~~~~~~~~~~~~
164
165 IPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to
166 restrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to
167 ``uv_udp_bind``.
168
169 Multicast
170 ~~~~~~~~~
171
172 A socket can (un)subscribe to a multicast group using:
173
174 .. code::block:: c
175
176 int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership);
177
178 where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``.
179
180 The concepts of multicasting are nicely explained in `this guide`_.
181
182 .. _this guide: https://www.tldp.org/HOWTO/Multicast-HOWTO-2.html
183
184 Local loopback of multicast packets is enabled by default [#]_, use
185 ``uv_udp_set_multicast_loop`` to switch it off.
186
187 The packet time-to-live for multicast packets can be changed using
188 ``uv_udp_set_multicast_ttl``.
189
190 Querying DNS
191 ------------
192
193 libuv provides asynchronous DNS resolution. For this it provides its own
194 ``getaddrinfo`` replacement [#]_. In the callback you can
195 perform normal socket operations on the retrieved addresses. Let's connect to
196 Libera.chat to see an example of DNS resolution.
197
198 .. rubric:: dns/main.c
199 .. literalinclude:: ../../code/dns/main.c
200 :language: c
201 :linenos:
202 :lines: 61-
203 :emphasize-lines: 12
204
205 If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and
206 your callback won't be invoked at all. All arguments can be freed immediately
207 after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints`
208 structures are documented in `the getaddrinfo man page <getaddrinfo_>`_. The
209 callback can be ``NULL`` in which case the function will run synchronously.
210
211 In the resolver callback, you can pick any IP from the linked list of ``struct
212 addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to
213 call ``uv_freeaddrinfo`` in the callback.
214
215 .. rubric:: dns/main.c
216 .. literalinclude:: ../../code/dns/main.c
217 :language: c
218 :linenos:
219 :lines: 42-60
220 :emphasize-lines: 8,16
221
222 libuv also provides the inverse `uv_getnameinfo`_.
223
224 .. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo
225
226 Network interfaces
227 ------------------
228
229 Information about the system's network interfaces can be obtained through libuv
230 using ``uv_interface_addresses``. This simple program just prints out all the
231 interface details so you get an idea of the fields that are available. This is
232 useful to allow your service to bind to IP addresses when it starts.
233
234 .. rubric:: interfaces/main.c
235 .. literalinclude:: ../../code/interfaces/main.c
236 :language: c
237 :linenos:
238 :emphasize-lines: 9,17
239
240 ``is_internal`` is true for loopback interfaces. Note that if a physical
241 interface has multiple IPv4/IPv6 addresses, the name will be reported multiple
242 times, with each address being reported once.
243
244 .. _c-ares: https://c-ares.haxx.se
245 .. _getaddrinfo: https://man7.org/linux/man-pages/man3/getaddrinfo.3.html
246
247 .. _User Datagram Protocol: https://en.wikipedia.org/wiki/User_Datagram_Protocol
248 .. _DHCP: https://tools.ietf.org/html/rfc2131
249
250 ----
251
252 .. [#] https://beej.us/guide/bgnet/html/#broadcast-packetshello-world
253 .. [#] https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1
254 .. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv
255 v0.8.0 and earlier also included c-ares_ as an alternative, but this has been
256 removed in v0.9.0.