Socket.IOは、双方向通信を実現してくれるNode.jsのライブラリです。ここでは、簡単なプログラムを通じて双方向通信の動作確認をします。(Client側もNode.jsを利用しており、実装はTypeScriptで行っています。)
WebSocketについて
WebSocketは、双方向通信を行うためのプロトコルです。通信のたびに新しくコネクションを確立する必要がなく、HTTPに比べて軽量なヘッダなので、双方向通信を低コストで実現できます。
ws:
と wss:
のURIスキームが定義されています。wss:
はTLSで暗号化されます。
ブラウザサポート状況は以下サイトで確認できます。
https://caniuse.com/websockets
Socket.IOについて
Socket.IOは、WebSocketの実装というわけではないですが、状況に合わせて WebSocket
や ロングポーリング
など利用して双方向通信を実現してくれます。
前準備
必要パッケージをインストールします。今回、Client側もnode.jsで確認するので socket.io-client
もインストールします。
npm init
npm install socket.io socket.io-client
処理は TypeScript
で記述します。
npm install --save-dev typescript
npx tsc --init
動作確認1|接続
まずは、接続だけ行います。
server.ts
import http from 'http';
import socketio from 'socket.io';
const server: http.Server = http.createServer();
const io: socketio.Server = new socketio.Server(server);
io.on('connection', (socket: socketio.Socket) => console.log('connect'));
const port = 5000;
server.listen(port, () => console.log(`app listening on port ${port}`));
client.ts
import { io } from 'socket.io-client';
const port = 5000;
const socket = io(`http://localhost:${port}`);
socket.on('connect', () => console.log('connect'));
動作確認

server.ts
だけ起動しています。

client.ts
も起動して接続されました。
動作確認2|Server – Client間で通信
( emit )
双方間通信を確認します。
server.ts
import http from 'http';
import socketio from 'socket.io';
const server: http.Server = http.createServer();
const io: socketio.Server = new socketio.Server(server);
io.on('connection', (socket: socketio.Socket) => {
console.log('connect');
let counter = 0;
// Clientからメッセージを受信
socket.on('yyy', (data: { message: string }) => {
console.log(`type: ${typeof data} data: ${data.message}`);
});
// Clientにメッセージを送信
setInterval(() => {
socket.emit('xxx', { message: `server message ${counter++}` });
}, 1000);
});
const port = 5000;
server.listen(port, () => {
console.log(`app listening on port ${port}`);
});
client.ts
import { io } from 'socket.io-client';
const port = 5000;
const socket = io(`http://localhost:${port}`);
socket.on('connect', () => {
console.log('connect');
});
// Serverからメッセージを受信
socket.on('xxx', (data: { message: string }) => {
console.log(`type: ${typeof data} data: ${data.message}`);
});
// Serverにメッセージを送信
let counter = 0;
setInterval(() => {
socket.emit('yyy', { message: `client message ${counter++}` });
}, 1000);
補足

serverからclientに xxx
eventを通じてメッセージを送信しています。
clientからserverに yyy
eventを通じてメッセージを送信しています。
動作確認

双方向の通信を確認できました。
動作確認2|任意の範囲内で通信
( room )
roomという機能が提供されており、roomにjoinしている範囲内で通信できます。
server.ts
import http from 'http';
import socketio from 'socket.io';
const server: http.Server = http.createServer();
const io: socketio.Server = new socketio.Server(server);
io.on('connection', (socket: socketio.Socket) => {
const socketId = socket.id;
console.log(`[connect] socketId: ${socketId}`);
let clientId = '';
let roomId = '';
let counter = 0;
// Clientからのメッセージを受信
socket.on('join_to_room', (data: { clientId: string; roomId: string }) => {
roomId = data.roomId;
clientId = data.clientId;
socket.join(roomId);
console.log(
`[join to room] socketId: ${socketId} clientId: ${clientId} roomId: ${roomId}`,
);
});
// Clientにメッセージを送信
setInterval(() => {
socket.to(roomId).emit('server_to_client', {
message: {
socketId,
clientId,
roomId,
counter: counter++,
},
});
}, 1000);
});
const port = 5000;
server.listen(port, () => {
console.log(`app listening on port ${port}`);
});
client.ts
実行時、引数で clientId
roomId
を指定できるようにしています。
import { io } from 'socket.io-client';
const port = 5000;
const socket = io(`http://localhost:${port}`);
const clientId = process.argv[2];
const roomId = process.argv[3];
console.log(`clientId: ${clientId} roomId: ${roomId}`);
socket.on('connect', () => {
console.log('connect');
});
// Serverからメッセージを受信
socket.on('server_to_client', (data: { message: object }) => {
console.log(JSON.stringify(data.message));
});
// Serverにメッセージを送信
socket.emit('join_to_room', { clientId, roomId });
補足

serverは、clientから join_to_room
eventを通じてメッセージを受信したタイミングで room
に join
します。
serverは、room
を指定したうえで、 server_to_client
eventを通じてclientにメッセージを送信しています。
動作確認
1. server.tsを起動

2. client.tsを起動(ClientA)

3. client.tsを起動(ClientB)
ClientAとは異なるroomIdを指定して起動します。

roomId
が異なるのでメッセージは表示されません。
4. client.tsを起動(ClientC)
ClientAとは同じ roomId
を指定して起動します。

ClientAとClientCで roomId
が同じなので、ClientAの画面にはClientCのメッセージが表示され、ClientCの画面にはClientAのメッセージが表示されています。
参考
WebSocket関連
- WebSocket – Wikipedia
- RFC 6455 – The WebSocket Protocol (日本語訳)
- WebSocket クライアントアプリケーションの記述 – Web API | MDN
- WebSocket サーバーの記述 – Web API | MDN
Socket.IO関連