Individual client connection management with bidirectional message passing, transport upgrades, and connection state tracking.
Represents an individual client connection with bidirectional communication capabilities.
/**
* Individual client connection with bidirectional communication
*/
class Socket extends EventEmitter {
/** Unique socket identifier (internal use only) */
private readonly id: string;
/** Protocol version (3 or 4) */
readonly protocol: number;
/** Current connection state */
readonly readyState: ReadyState;
/** Current transport instance */
readonly transport: Transport;
/** Initial HTTP request object */
readonly request: IncomingMessage;
/** Client IP address */
readonly remoteAddress: string;
/** Whether transport upgrade is in progress */
readonly upgrading: boolean;
/** Whether transport has been upgraded */
readonly upgraded: boolean;
/**
* Create socket instance (internal use)
* @param id - Unique socket identifier
* @param server - Parent server instance
* @param transport - Initial transport
* @param req - Extended HTTP request with Engine.IO properties
* @param protocol - Protocol version
*/
constructor(
id: string,
server: BaseServer,
transport: Transport,
req: EngineRequest,
protocol: number
);
}/**
* Send data to the client
* @param data - String or Buffer data to send
* @param options - Send options
* @param callback - Optional callback when sent
*/
send(
data: RawData,
options?: SendOptions,
callback?: (transport: Transport) => void
): Socket;
/**
* Alias for send() method
*/
write(
data: RawData,
options?: SendOptions,
callback?: (transport: Transport) => void
): Socket;Usage Examples:
// Send text message
socket.send('Hello client!');
// Send binary data
socket.send(Buffer.from([1, 2, 3, 4]));
// Send with compression disabled
socket.send('Large text data', { compress: false });
// Send with callback
socket.send('Message', undefined, (transport) => {
console.log('Message sent via transport:', transport.name);
});
// Method chaining (since send returns Socket)
socket.send('First message').send('Second message');/**
* Close the socket connection
* @param discard - Whether to discard the connection immediately
*/
close(discard?: boolean): void;Usage Example:
// Graceful close
socket.close();
// Immediate close (discard pending data)
socket.close(true);interface SocketEvents {
/** Emitted when socket connection is established */
open: () => void;
/** Emitted when socket connection is closed */
close: (reason: string, description?: any) => void;
/** Emitted when data is received from client */
data: (data: string | Buffer) => void;
/** Alias for 'data' event */
message: (data: string | Buffer) => void;
/** Emitted when a packet is received */
packet: (packet: Packet) => void;
/** Emitted when a packet is created for sending */
packetCreate: (packet: Packet) => void;
/** Emitted on ping/pong heartbeat */
heartbeat: () => void;
/** Emitted when transport upgrade starts */
upgrading: (transport: Transport) => void;
/** Emitted when transport upgrade completes */
upgrade: (transport: Transport) => void;
/** Emitted when write buffer is flushed */
flush: (buffer: any[]) => void;
/** Emitted when ready to write more data */
drain: () => void;
/** Emitted on socket errors */
error: (error: Error) => void;
}Usage Examples:
socket.on('open', () => {
console.log('Socket opened:', socket.id);
socket.send('Welcome!');
});
socket.on('message', (data) => {
console.log('Received from', socket.id, ':', data);
// Echo the message back
socket.send(`Echo: ${data}`);
});
socket.on('close', (reason, description) => {
console.log('Socket closed:', socket.id, reason);
});
socket.on('upgrade', (transport) => {
console.log('Transport upgraded to:', transport.name);
});
socket.on('error', (error) => {
console.error('Socket error:', error);
});/**
* Socket connection states
*/
enum ReadyState {
OPENING = "opening",
OPEN = "open",
CLOSING = "closing",
CLOSED = "closed"
}/**
* Options for sending messages
*/
interface SendOptions {
/** Whether to compress the message (default: true for large messages) */
compress?: boolean;
}// Server-side request-response
socket.on('message', (data) => {
const request = JSON.parse(data);
if (request.type === 'ping') {
socket.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
}
});// Broadcast to all connected clients
function broadcast(message: string) {
Object.values(server.clients).forEach(socket => {
if (socket.readyState === 'open') {
socket.send(message);
}
});
}
// Usage
server.on('connection', (socket) => {
// Notify others of new connection
broadcast(`User ${socket.id} joined`);
socket.on('message', (data) => {
// Broadcast message to other clients
Object.values(server.clients).forEach(otherSocket => {
if (otherSocket !== socket && otherSocket.readyState === 'open') {
otherSocket.send(`${socket.id}: ${data}`);
}
});
});
socket.on('close', () => {
broadcast(`User ${socket.id} left`);
});
});socket.on('message', (data) => {
if (Buffer.isBuffer(data)) {
console.log('Received binary data:', data.length, 'bytes');
// Process binary data
const processed = processImageData(data);
socket.send(processed);
} else {
console.log('Received text data:', data);
socket.send(`Text echo: ${data}`);
}
});// Track active connections
const activeConnections = new Map<string, Socket>();
server.on('connection', (socket) => {
activeConnections.set(socket.id, socket);
console.log('Active connections:', activeConnections.size);
socket.on('close', () => {
activeConnections.delete(socket.id);
console.log('Active connections:', activeConnections.size);
});
});const MAX_CONNECTIONS = 1000;
server.on('connection', (socket) => {
if (server.clientsCount > MAX_CONNECTIONS) {
socket.send('Server full');
socket.close();
return;
}
// Handle connection normally
socket.on('message', handleMessage);
});socket.on('heartbeat', () => {
console.log('Heartbeat from:', socket.id);
socket.lastSeen = Date.now();
});
// Check for stale connections
setInterval(() => {
const now = Date.now();
Object.values(server.clients).forEach(socket => {
if (now - socket.lastSeen > 60000) { // 60 seconds
console.log('Closing stale connection:', socket.id);
socket.close();
}
});
}, 30000);