Understanding WebRTC: Architecture, NAT Traversal, and a Complete Demo
This article explains WebRTC fundamentals, compares it with WebSocket, describes SDP, ICE, STUN/TURN NAT traversal, and provides full server‑side and client‑side JavaScript code to build a peer‑to‑peer video conferencing demo.
Keywords : NAT (Network Address Translation), STUN (Session Traversal Utilities for NAT), TURN (Traversal Using Relays around NAT), ICE (Interactive Connectivity Establishment), SDP (Session Description Protocol), WebRTC (Web Real‑Time Communications).
WebRTC is a real‑time communication technology that enables browsers to establish peer‑to‑peer connections for audio, video, or arbitrary data streams without an intermediate server; it must run over HTTPS.
WebRTC vs WebSocket
WebSocket provides full‑duplex communication between a browser and a web server.
WebRTC provides full‑duplex communication directly between two browsers.
WebSocket uses TCP, while WebRTC uses UDP.
WebSocket traffic always passes through a server; WebRTC traffic is direct, saving bandwidth.
WebSocket latency is higher; WebRTC latency is lower.
In practice, WebRTC often works together with WebSocket, where WebSocket is used only to exchange SDP and network information needed to set up the WebRTC connection.
Offer/Answer Exchange
Similar to TCP three‑way handshake, WebRTC requires an offer/answer exchange (at least four messages) to negotiate connection parameters. An example flow can be seen in the demo at https://nashaofu.github.io/webrtc-demo/socket.html .
After exchanging offers and answers, WebRTC attempts a direct connection using the peers' IP addresses and ports; this is where NAT traversal ("hole punching") occurs.
Signaling Server
Since WebRTC does not define a signaling mechanism, any channel (e.g., WebSocket, XMLHttpRequest) can be used to exchange tokens such as SDP and ICE candidates between peers.
Data Transmission Support
WebRTC supports audio/video streams and also arbitrary data via a bidirectional dataChannel . Example code for adding a video track:
const pc = new RTCPeerConnection();
navigator.getUserMedia({video: true}, stream => {
// Add video tracks to the session
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// Show local video
$localVideo.srcObject = stream;
});Example code for using a data channel to send text messages:
const pc = new RTCPeerConnection();
const dataChannel = pc.createDataChannel('chat');
pc.addEventListener('datachannel', event => {
event.channel.addEventListener('message', e => console.log('message', e.message));
});
dataChannel.addEventListener('open', () => {
dataChannel.send('Hi!');
});Session Description Protocol (SDP)
Offers and answers contain SDP text that describes media capabilities, codecs, bandwidth, and transport details. An SDP object looks like:
{
type: "offer" | "answer",
sdp: string
}A typical SDP snippet includes version, origin, session name, connection data, and media announcements (audio, video, etc.).
ICE Candidate Event
When RTCPeerConnection.setLocalDescription() is called, the browser gathers local network candidates and emits a candidate event containing IP address, port, candidate type (host, srflx, relay), priority, and protocol.
{
"address": "192.168.31.67",
"candidate": "candidate:2147606101 1 udp 2122260223 192.168.31.67 57959 typ host ...",
"component": "rtp",
"foundation": "2147606101",
"port": 57959,
"priority": 2122260223,
"protocol": "udp",
"type": "host",
"usernameFragment": "EaWw"
}Candidate types:
host : address from the local network interface.
srflx : server‑reflexive address returned by a STUN server.
relay : relayed address allocated by a TURN server.
Network Address Translation (NAT)
NAT rewrites source or destination IP addresses and ports as packets pass through a router or firewall, allowing many private devices to share a single public IP address. NAT maintains a mapping table of internal IP:port ↔ external IP:port.
Different NAT types (full‑cone, restricted‑cone, port‑restricted, symmetric) affect the success of peer‑to‑peer connections.
NAT Traversal (Hole Punching)
WebRTC implements NAT hole punching automatically using ICE, which combines STUN (to discover public IP/port) and TURN (to relay traffic when direct connection fails). If hole punching fails, TURN is used as a fallback.
Demo Implementation
Signaling server (Node.js + socket.io) :
const socket = require('socket.io');
module.exports = server => {
const io = socket.listen(server);
io.sockets.on('connection', function(socket) {
socket.on('disconnecting', () => {
Object.keys(socket.rooms).forEach(room => {
socket.broadcast.to(room).emit('leaveed', socket.id);
});
});
socket.on('message', function(target, message) {
if (target) {
io.sockets.sockets[target]?.emit('message', message);
}
});
socket.on('create or join', function(room) {
const clientsInRoom = io.sockets.adapter.rooms[room];
const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
if (numClients === 0) {
socket.join(room);
socket.emit('created', room, socket.id);
} else if (numClients < 10) {
socket.join(room);
socket.emit('joined', room, socket.id);
socket.broadcast.to(room).emit('message', {socketId: socket.id, type: 'join'});
} else {
socket.emit('full', room);
}
});
});
};Client side (browser JavaScript) creates a RTCPeerConnection , obtains local media, handles ICE candidates, and processes signaling messages (join, offer, answer, candidate). The code also manages room creation/joining, video element insertion, and cleanup when peers leave.
const videos = document.querySelector('#videos');
const localVideo = document.querySelector('#localVideo');
const socket = io.connect();
// ... getUserMedia, createRTC, sendMsg, handle 'message' events, etc.Full source code and additional examples are available at https://github.com/nashaofu/webrtc-demo .
Images illustrating NAT mapping, ICE flow, and the demo UI are included in the original article.
ByteDance ADFE Team
Official account of ByteDance Advertising Frontend Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.