The dgram module provides UDP datagram sockets for connectionless networking. Here's how to use it.
Basic UDP Server#
1import dgram from 'node:dgram';
2
3const server = dgram.createSocket('udp4');
4
5server.on('error', (err) => {
6 console.error('Server error:', err);
7 server.close();
8});
9
10server.on('message', (msg, rinfo) => {
11 console.log(`Received: ${msg} from ${rinfo.address}:${rinfo.port}`);
12
13 // Send response
14 const response = Buffer.from('Message received');
15 server.send(response, rinfo.port, rinfo.address);
16});
17
18server.on('listening', () => {
19 const address = server.address();
20 console.log(`Server listening on ${address.address}:${address.port}`);
21});
22
23server.bind(41234);Basic UDP Client#
1import dgram from 'node:dgram';
2
3const client = dgram.createSocket('udp4');
4
5const message = Buffer.from('Hello, server!');
6
7client.send(message, 41234, 'localhost', (err) => {
8 if (err) {
9 console.error('Send error:', err);
10 client.close();
11 return;
12 }
13 console.log('Message sent');
14});
15
16client.on('message', (msg, rinfo) => {
17 console.log(`Response: ${msg} from ${rinfo.address}:${rinfo.port}`);
18 client.close();
19});
20
21// Set timeout for response
22setTimeout(() => {
23 console.log('No response received');
24 client.close();
25}, 5000);UDP Echo Server#
1import dgram from 'node:dgram';
2
3const server = dgram.createSocket('udp4');
4
5server.on('message', (msg, rinfo) => {
6 console.log(`Echo: ${msg}`);
7
8 // Echo back the message
9 server.send(msg, rinfo.port, rinfo.address, (err) => {
10 if (err) console.error('Echo error:', err);
11 });
12});
13
14server.bind(41234, () => {
15 console.log('Echo server running on port 41234');
16});IPv6 Support#
1import dgram from 'node:dgram';
2
3// IPv6 socket
4const server6 = dgram.createSocket('udp6');
5
6server6.on('message', (msg, rinfo) => {
7 console.log(`IPv6 message: ${msg} from [${rinfo.address}]:${rinfo.port}`);
8});
9
10server6.bind(41234, '::', () => {
11 console.log('IPv6 server running');
12});
13
14// Dual-stack socket (IPv4 and IPv6)
15const dualStack = dgram.createSocket({
16 type: 'udp6',
17 ipv6Only: false,
18});
19
20dualStack.bind(41235, () => {
21 console.log('Dual-stack server running');
22});Multicast#
1import dgram from 'node:dgram';
2
3const MULTICAST_ADDR = '224.1.1.1';
4const PORT = 5000;
5
6// Multicast sender
7function createSender() {
8 const sender = dgram.createSocket('udp4');
9
10 setInterval(() => {
11 const message = Buffer.from(`Time: ${Date.now()}`);
12 sender.send(message, PORT, MULTICAST_ADDR, (err) => {
13 if (err) console.error('Multicast send error:', err);
14 });
15 }, 1000);
16
17 return sender;
18}
19
20// Multicast receiver
21function createReceiver() {
22 const receiver = dgram.createSocket({
23 type: 'udp4',
24 reuseAddr: true,
25 });
26
27 receiver.on('message', (msg, rinfo) => {
28 console.log(`Multicast: ${msg} from ${rinfo.address}`);
29 });
30
31 receiver.bind(PORT, () => {
32 receiver.addMembership(MULTICAST_ADDR);
33 console.log('Joined multicast group');
34 });
35
36 return receiver;
37}
38
39const sender = createSender();
40const receiver = createReceiver();Broadcast#
1import dgram from 'node:dgram';
2
3const BROADCAST_ADDR = '255.255.255.255';
4const PORT = 5001;
5
6// Broadcast sender
7function createBroadcaster() {
8 const socket = dgram.createSocket('udp4');
9
10 socket.bind(() => {
11 socket.setBroadcast(true);
12
13 setInterval(() => {
14 const message = Buffer.from('Broadcast message');
15 socket.send(message, PORT, BROADCAST_ADDR, (err) => {
16 if (err) console.error('Broadcast error:', err);
17 });
18 }, 1000);
19 });
20
21 return socket;
22}
23
24// Broadcast receiver
25function createBroadcastReceiver() {
26 const socket = dgram.createSocket({
27 type: 'udp4',
28 reuseAddr: true,
29 });
30
31 socket.on('message', (msg, rinfo) => {
32 console.log(`Broadcast received: ${msg} from ${rinfo.address}`);
33 });
34
35 socket.bind(PORT);
36
37 return socket;
38}Socket Options#
1import dgram from 'node:dgram';
2
3const socket = dgram.createSocket({
4 type: 'udp4',
5 reuseAddr: true, // Allow multiple sockets on same port
6 recvBufferSize: 65536, // Receive buffer size
7 sendBufferSize: 65536, // Send buffer size
8});
9
10socket.bind(41234, () => {
11 // Set TTL (Time To Live)
12 socket.setTTL(128);
13
14 // Set multicast TTL
15 socket.setMulticastTTL(2);
16
17 // Enable multicast loopback
18 socket.setMulticastLoopback(true);
19
20 // Get/set receive buffer size
21 console.log('Recv buffer:', socket.getRecvBufferSize());
22 socket.setRecvBufferSize(131072);
23
24 // Get/set send buffer size
25 console.log('Send buffer:', socket.getSendBufferSize());
26 socket.setSendBufferSize(131072);
27});Message Framing#
1import dgram from 'node:dgram';
2
3// Simple message protocol
4class UDPProtocol {
5 constructor(socket) {
6 this.socket = socket;
7 this.handlers = new Map();
8 }
9
10 // Send structured message
11 send(type, data, port, address) {
12 const message = JSON.stringify({ type, data });
13 const buffer = Buffer.from(message);
14
15 return new Promise((resolve, reject) => {
16 this.socket.send(buffer, port, address, (err) => {
17 if (err) reject(err);
18 else resolve();
19 });
20 });
21 }
22
23 // Register message handler
24 on(type, handler) {
25 this.handlers.set(type, handler);
26 }
27
28 // Process incoming messages
29 listen() {
30 this.socket.on('message', (msg, rinfo) => {
31 try {
32 const { type, data } = JSON.parse(msg.toString());
33 const handler = this.handlers.get(type);
34 if (handler) {
35 handler(data, rinfo);
36 }
37 } catch (err) {
38 console.error('Parse error:', err);
39 }
40 });
41 }
42}
43
44// Usage
45const socket = dgram.createSocket('udp4');
46const protocol = new UDPProtocol(socket);
47
48protocol.on('ping', (data, rinfo) => {
49 console.log('Ping received from', rinfo.address);
50 protocol.send('pong', { time: Date.now() }, rinfo.port, rinfo.address);
51});
52
53protocol.on('pong', (data, rinfo) => {
54 console.log('Pong received:', data.time);
55});
56
57protocol.listen();
58socket.bind(41234);Service Discovery#
1import dgram from 'node:dgram';
2import os from 'node:os';
3
4const DISCOVERY_PORT = 5002;
5const MULTICAST_ADDR = '224.0.0.1';
6
7class ServiceDiscovery {
8 constructor(serviceName, servicePort) {
9 this.serviceName = serviceName;
10 this.servicePort = servicePort;
11 this.socket = dgram.createSocket({
12 type: 'udp4',
13 reuseAddr: true,
14 });
15 this.peers = new Map();
16 }
17
18 start() {
19 this.socket.on('message', (msg, rinfo) => {
20 try {
21 const data = JSON.parse(msg.toString());
22 this.handleMessage(data, rinfo);
23 } catch (err) {
24 // Ignore invalid messages
25 }
26 });
27
28 this.socket.bind(DISCOVERY_PORT, () => {
29 this.socket.addMembership(MULTICAST_ADDR);
30 this.socket.setBroadcast(true);
31
32 // Announce presence
33 this.announce();
34
35 // Periodic announcements
36 setInterval(() => this.announce(), 5000);
37
38 // Clean up stale peers
39 setInterval(() => this.cleanupPeers(), 10000);
40 });
41 }
42
43 announce() {
44 const message = JSON.stringify({
45 type: 'announce',
46 service: this.serviceName,
47 port: this.servicePort,
48 hostname: os.hostname(),
49 });
50
51 this.socket.send(
52 Buffer.from(message),
53 DISCOVERY_PORT,
54 MULTICAST_ADDR
55 );
56 }
57
58 handleMessage(data, rinfo) {
59 if (data.type === 'announce') {
60 const key = `${rinfo.address}:${data.port}`;
61 this.peers.set(key, {
62 address: rinfo.address,
63 port: data.port,
64 service: data.service,
65 hostname: data.hostname,
66 lastSeen: Date.now(),
67 });
68 }
69 }
70
71 cleanupPeers() {
72 const now = Date.now();
73 for (const [key, peer] of this.peers) {
74 if (now - peer.lastSeen > 15000) {
75 this.peers.delete(key);
76 console.log('Peer removed:', key);
77 }
78 }
79 }
80
81 getPeers() {
82 return Array.from(this.peers.values());
83 }
84}
85
86// Usage
87const discovery = new ServiceDiscovery('my-app', 8080);
88discovery.start();
89
90setInterval(() => {
91 console.log('Known peers:', discovery.getPeers());
92}, 5000);UDP with Promises#
1import dgram from 'node:dgram';
2
3class UDPClient {
4 constructor() {
5 this.socket = dgram.createSocket('udp4');
6 this.pending = new Map();
7 this.messageId = 0;
8
9 this.socket.on('message', (msg, rinfo) => {
10 try {
11 const data = JSON.parse(msg.toString());
12 const pending = this.pending.get(data.id);
13 if (pending) {
14 clearTimeout(pending.timeout);
15 this.pending.delete(data.id);
16 pending.resolve(data.response);
17 }
18 } catch (err) {
19 // Ignore parse errors
20 }
21 });
22 }
23
24 send(message, port, address, timeout = 5000) {
25 return new Promise((resolve, reject) => {
26 const id = ++this.messageId;
27
28 const timeoutId = setTimeout(() => {
29 this.pending.delete(id);
30 reject(new Error('Request timeout'));
31 }, timeout);
32
33 this.pending.set(id, {
34 resolve,
35 reject,
36 timeout: timeoutId,
37 });
38
39 const data = JSON.stringify({ id, request: message });
40 this.socket.send(Buffer.from(data), port, address, (err) => {
41 if (err) {
42 clearTimeout(timeoutId);
43 this.pending.delete(id);
44 reject(err);
45 }
46 });
47 });
48 }
49
50 close() {
51 this.socket.close();
52 }
53}
54
55// Usage
56const client = new UDPClient();
57
58async function main() {
59 try {
60 const response = await client.send(
61 { action: 'getData' },
62 41234,
63 'localhost'
64 );
65 console.log('Response:', response);
66 } catch (err) {
67 console.error('Error:', err.message);
68 } finally {
69 client.close();
70 }
71}Error Handling#
1import dgram from 'node:dgram';
2
3const socket = dgram.createSocket('udp4');
4
5socket.on('error', (err) => {
6 console.error('Socket error:', err.message);
7
8 // Handle specific errors
9 switch (err.code) {
10 case 'EADDRINUSE':
11 console.log('Port already in use');
12 break;
13 case 'EACCES':
14 console.log('Permission denied');
15 break;
16 case 'ENETUNREACH':
17 console.log('Network unreachable');
18 break;
19 default:
20 console.log('Unknown error:', err.code);
21 }
22
23 socket.close();
24});
25
26socket.on('close', () => {
27 console.log('Socket closed');
28});
29
30// Graceful shutdown
31process.on('SIGINT', () => {
32 console.log('Shutting down...');
33 socket.close(() => {
34 process.exit(0);
35 });
36});
37
38socket.bind(41234);Best Practices#
Socket Configuration:
✓ Use reuseAddr for multiple listeners
✓ Set appropriate buffer sizes
✓ Handle all error events
✓ Clean up on close
Message Handling:
✓ Validate incoming data
✓ Implement timeouts
✓ Handle partial messages
✓ Use sequence numbers
Multicast:
✓ Join/leave groups properly
✓ Set appropriate TTL
✓ Handle loopback
✓ Use reuseAddr
Avoid:
✗ Ignoring errors
✗ Assuming delivery
✗ Large datagrams (>512 bytes safe)
✗ Blocking operations
Conclusion#
The Node.js dgram module provides UDP networking for connectionless communication. Use it for real-time applications, service discovery, broadcasts, and multicast scenarios where occasional packet loss is acceptable. Always handle errors, implement timeouts for request-response patterns, and keep messages small for reliable delivery. For guaranteed delivery or streaming data, consider TCP with the net module instead.