* Copyright (C) 2026 Huawei Device Co., Ltd.
*
* This software is distributed under a license. The full license
* agreement can be found in the file LICENSE in this distribution.
* This software may not be copied, modified, sold or distributed
* other than expressed in the named license agreement.
*
* This software is distributed without any warranty.
*/
* @ohos/socketio Demo 测试服务端
*
* 端口:6600
* 支持的 Demo 列表:
* 001 - Socket连接建立与状态查询 → 建立连接即可触发 open_listener
* 002 - 连接全生命周期监听 → 建立/断开连接触发各生命周期回调
* 003 - Socket命名空间配置与监听 → /test 命名空间 echo
* 004 - 事件发送与接收 → chat 事件 echo
* 005 - 多参数事件与一次性监听 → multiEvent echo、onceEvent echo
* 006 - 二进制事件收发 → binaryEvent echo(Buffer)
* 007 - ACK确认回调发送 → ackEvent ACK 回调、binaryAckEvent 二进制 ACK
* 008 - 错误事件监听与取消 → 连接无效地址由客户端触发,服务端无需特殊处理
* 009 - HTTP请求头与连接选项配置 → 服务端打印 handshake headers 验证
* 010 - 重连策略参数配置 → 服务端可主动断开连接触发重连
* 011 - 连接关闭与监听器清理 → 建立/断开连接即可
* 012 - 代理服务器认证配置 → 需通过代理连接,服务端正常监听即可
*
* 启动方式:
* npm install
* npm start
*
* 或直接:node index.js
*/
'use strict';
const { Server } = require('socket.io');
const http = require('http');
const PORT = 6600;
const httpServer = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('@ohos/socketio demo server is running on port ' + PORT + '\n');
});
const io = new Server(httpServer, {
cors: {
origin: '*',
methods: ['GET', 'POST']
},
allowEIO3: true
});
console.log('='.repeat(60));
console.log(' @ohos/socketio Demo 测试服务端');
console.log(' 端口: ' + PORT);
console.log('='.repeat(60));
io.on('connection', (socket) => {
console.log('\n[/] 新连接 socket.id=' + socket.id);
const headers = socket.handshake.headers;
if (headers['authorization']) {
console.log('[/] [Demo009] Authorization header: ' + headers['authorization']);
}
if (headers['x-custom-header']) {
console.log('[/] [Demo009] custom header: ' + headers['x-custom-header']);
}
socket.on('chat', (...args) => {
console.log('[/] [Demo004] chat received:', args);
socket.emit('chat', ...args);
});
socket.on('multiEvent', (...args) => {
console.log('[/] [Demo005] multiEvent received, args count=' + args.length, args);
socket.emit('multiEvent', ...args);
});
socket.on('onceEvent', (...args) => {
console.log('[/] [Demo005] onceEvent received:', args);
socket.emit('onceEvent', ...args);
});
socket.on('binaryEvent', (...args) => {
const data = args[0];
if (Buffer.isBuffer(data)) {
console.log('[/] [Demo006] binaryEvent received, Buffer length=' + data.length);
} else if (data instanceof Uint8Array || ArrayBuffer.isView(data)) {
console.log('[/] [Demo006] binaryEvent received, TypedArray length=' + data.byteLength);
} else {
console.log('[/] [Demo006] binaryEvent received (non-binary):', data);
}
socket.emit('binaryEvent', data);
});
socket.on('ackEvent', (...args) => {
console.log('[/] [Demo007] ackEvent received:', args);
const ackFn = args[args.length - 1];
if (typeof ackFn === 'function') {
const response = {
status: 'ok',
echo: args.slice(0, -1),
timestamp: Date.now()
};
console.log('[/] [Demo007] calling ACK callback with:', response);
ackFn(response);
}
});
socket.on('binaryAckEvent', (...args) => {
console.log('[/] [Demo007] binaryAckEvent received:', args);
const ackFn = args[args.length - 1];
if (typeof ackFn === 'function') {
const code = 200;
const binaryData = Buffer.from('ACK_OK');
console.log('[/] [Demo007] calling binary ACK, code=' + code + ', data=' + binaryData.toString());
ackFn(code, binaryData);
}
});
socket.on('admin_disconnect', () => {
console.log('[/] [Demo010] admin_disconnect: server disconnecting socket ' + socket.id);
socket.disconnect(true);
});
socket.on('ping_test', (data) => {
console.log('[/] ping_test received:', data);
socket.emit('pong_test', { echo: data, ts: Date.now() });
});
socket.on('disconnect', (reason) => {
console.log('[/] 连接断开 socket.id=' + socket.id + ' reason=' + reason);
});
socket.on('error', (err) => {
console.error('[/] socket error:', err);
});
});
const nspTest = io.of('/test');
nspTest.on('connection', (socket) => {
console.log('\n[/test] 新连接 socket.id=' + socket.id);
socket.on('echo', (data) => {
console.log('[/test] echo received:', data);
socket.emit('echo', data);
});
socket.on('chat', (...args) => {
console.log('[/test] chat received:', args);
socket.emit('chat', ...args);
});
socket.on('disconnect', (reason) => {
console.log('[/test] 连接断开 socket.id=' + socket.id + ' reason=' + reason);
});
});
const nspErrorTest = io.of('/error-test');
nspErrorTest.use((socket, next) => {
console.log('\n[/error-test] 收到连接请求,故意拒绝 socket.id=' + socket.id);
next(new Error('Demo008_intentional_auth_error: 命名空间连接被服务端拒绝'));
});
nspErrorTest.on('connection', () => {
});
httpServer.listen(PORT, () => {
console.log('\n服务端已启动,监听端口 ' + PORT);
console.log('客户端连接地址: http://<本机IP>:' + PORT);
console.log('\n支持的事件(默认命名空间 /):');
console.log(' chat → echo(Demo 004)');
console.log(' multiEvent → echo 多参数(Demo 005)');
console.log(' onceEvent → echo(Demo 005)');
console.log(' binaryEvent → echo Buffer(Demo 006)');
console.log(' ackEvent → ACK 回调 {status,echo,timestamp}(Demo 007)');
console.log(' binaryAckEvent→ 二进制 ACK code=200 + Buffer(ACK_OK)(Demo 007)');
console.log(' admin_disconnect → 服务端主动断开触发重连(Demo 010)');
console.log(' ping_test → pong_test echo(通用连通性)');
console.log('\n支持的命名空间:');
console.log(' /test → echo/chat(Demo 003)');
console.log(' /error-test → 始终拒绝命名空间连接,触发客户端 on_error(Demo 008)');
console.log('='.repeat(60));
});