WebSocket in Angular
Let’s explore how to use WebSockets with Angular. Due to the extensive nature of the topic, this guide will focus on utilizing standard WebSockets provided by JavaScript. A subsequent discussion will delve into leveraging RxJS for WebSocket implementation.
A crucial consideration with WebSockets is the protocol requirement: HTTPS sites must use wss, while HTTP sites should use ws.
Backend Setup
For testing purposes, we’ll construct a simple backend using Node.js.
Node.js Project Initialization
First, initialize a new Node.js project by executing the following command:
npm init
To enable WebSocket functionality, install the ws package:
npm i ws
Create a JavaScript file (e.g., index.js) to house the server code. The setup is now complete.
Initial Code Structure
The primary task is to import ws and configure the WebSocket server. This section presents a fundamental code snippet, omitting extraneous details. While the port can be chosen arbitrarily, it’s advisable to avoid reserved ports (e.g., 8080, 443).
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 8001 });
This code establishes a WebSocket connection through port 8001.
Handling Connections
The wss variable, representing the WebSocket server, is used to listen for connection events. All WebSocket-related logic should reside within this connection event handler.
wss.on('connection', ws => {
})
When a client initiates a connection (handshake), a connection event is triggered. You can verify this by logging a message to the console within the event handler.
Receiving Client Messages
To receive messages sent by the client, use the message event handler.
wss.on('connection', ws => {
ws.on('message', message => {
})
})
Sending Messages: send
To transmit messages to a client, use the send method.
ws.send(
JSON.stringify({data: 'message from server'})
);
The message parameter accepts data of any type. However, due to browser inconsistencies, particularly with older browsers that may only accept strings, it’s common practice to serialize data (e.g., using JSON.stringify) and parse it on the client-side.
The send method transmits messages to a specific client, enabling individualized communication with each connected client.
Handling Connection Closure
A close event is emitted when a client or server connection is terminated. Strictly speaking, the event is triggered just before the connection closes, allowing for a final message to be sent to the client.
ws.on('close', (code, reason) => {
})
Error Handling
An error event is triggered if issues arise during the connection.
ws.on('error', (err) => {
})
Broadcasting Messages
It’s possible to send messages to all connected clients simultaneously.
Unlike the send method, there isn’t a dedicated “broadcast” command. Instead, implement broadcasting by iterating over all connected clients and sending the message to each one individually. The wss variable stores information about all connected clients. The following code demonstrates how to retrieve this information and send a message to each client:
wss.on('connection', ws => {
wss.clients.forEach(client => {
client.send();
})
})
Frontend Implementation
This section focuses on the service responsible for establishing the WebSocket connection.
Connection Establishment
Establishing a connection on the frontend is relatively straightforward. Similar to the backend, event handling code should be added after the connection is opened. The WebSocket object provides fundamental state values:
- 0: CONNECTING
- 1: OPEN
- 2: CLOSING
- 3: CLOSED
Communication with the server can only occur after the connection state transitions to 1 (OPEN). Ensure this state is verified before sending or receiving messages.
@Injectable({
providedIn: 'root',
standalone: true,
})
export class NetworkService {
ws = new WebSocket('ws://localhost:8001');
connect() {
if(this.ws.readyState === WebSocket.OPEN) {
}
}
}
ending Messages to the Server
Use the send method, mirroring the backend implementation. While the send method accepts any data type, it’s advisable to serialize data (e.g., using JSON.stringify) for consistency, and handle parsing on the backend.
connect() {
if(this.ws.readyState === WebSocket.OPEN) {
this.ws.send(
JSON.stringify({data: 'message from client'})
)
}
}
Receiving Server Messages
To receive messages from the backend, listen for the onmessage event. The onmessage event handler receives a MessageEvent object as a parameter, which contains the data sent by the server.
...
this.ws.onmessage = (e: MessageEvent) => {
const response: NetworkResponse = JSON.parse(e.data);
}
Handling Connection Closure
If the server sends a message upon connection closure, the onclose event handler can be used to receive it. Note that the onclose event handler receives a CloseEvent parameter, which differs from the MessageEvent.
...
this.ws.onclose = (e: CloseEvent) => {
...
}
If no message is sent upon closure, the ws.readyState property can be compared to WebSocket.CLOSING or WebSocket.CLOSED to determine the connection state.
if(this.ws.readyState === WebSocket.CLOSING) { // or WebSocket.CLOSE
...
}
댓글남기기