Socket.IO 实时双向通信

精选 Socket.IO 实时双向通信 常用指令与核心速查备忘单,涵盖高频用法、配置参数与实用技巧。

#服务连接与初始化 (Connecting / Setup)

#JavaScript (Browser Client then Node.js Server)

Client

import { io } from 'socket.io-client';
const socket = io('http://localhost:3000');

Server

const io = require('socket.io')(3000, {
  cors: { origin: '*' }
});
io.on('connection', (socket) => {
  console.log('Client connected:', socket.id);
});

#Python (Client then Server)

Client

import socketio
sio = socketio.Client()
sio.connect('http://localhost:3000')

Server

import socketio, eventlet, flask

app = flask.Flask(__name__)
sio = socketio.Server(cors_allowed_origins='*')
app = socketio.WSGIApp(sio, app)

@sio.event
def connect(sid, environ):
    print('Client connected:', sid)

if __name__ == '__main__':
    eventlet.wsgi.server(eventlet.listen(('', 3000)), app)

#Java (Client then Server)

Client

IO.Options opts = new IO.Options();
Socket socket = IO.socket("http://localhost:3000", opts);
socket.connect();

Server

import io.socket.engineio.server.EngineIoServer;
import io.socket.server.SocketIoServer;

EngineIoServer engineIo = new EngineIoServer();
SocketIoServer io = new SocketIoServer(engineIo);
io.listen(3000);

io.on("connection", args -> {
    var client = args[0];
    System.out.println("Client connected: " + client.id());
});

#Swift (iOS Client then Server)

Client

let manager = SocketManager(
  socketURL: URL(string: "http://localhost:3000")!,
  config: [.log(true), .compress]
)
let socket = manager.defaultSocket
socket.connect()

Server Server setups in Swift are uncommon; usually Node.js or Python is used.

#C# (.NET Client then Server)

Client

var socket = IO.Socket("http://localhost:3000");
socket.Connect();

Server

using Fleck;
var server = new WebSocketServer("ws://0.0.0.0:3000");
server.Start(socket =>
{
    socket.OnOpen = () => Console.WriteLine("Client connected");
});

#React Native (Client)

Client

import io from 'socket.io-client';
const socket = io('http://localhost:3000');

(Server side same as JavaScript above.)

#Go (Client then Server)

Client

import "github.com/googollee/go-socket.io-client"
socket, err := gosocketio.Dial(
    gosocketio.GetUrl("localhost", 3000, false),
    transport.GetDefaultWebsocketTransport(),
)

Server

import (
    "github.com/googollee/go-socket.io"
    "net/http"
)

server, _ := socketio.NewServer(nil)
server.OnConnect("/", func(s socketio.Conn) error {
    fmt.Println("Client connected:", s.ID())
    return nil
})
http.Handle("/socket.io/", server)
go http.ListenAndServe(":3000", nil)

#Rust (Client then Server)

Client

use socketio_client::ClientBuilder;

async fn run() -> Result<(), Box<dyn std::error::Error>> {
    let socket = ClientBuilder::new("http://localhost:3000")
        .transport("websocket")
        .connect()
        .await?;
    Ok(())
}

Server Rust server support is experimental; commonly use Node.js/Python servers.


#事件发送与监听 (Emitting & Listening to Events)

#JavaScript (Client then Server)

Client

socket.emit('msg', 'Hi');
socket.on('reply', (data) => console.log('Reply:', data));

Server

io.on('connection', (socket) => {
  socket.on('msg', (msg) => {
    console.log('Received:', msg);
    socket.emit('reply', 'Hello from server');
  });
});

#Python (Client then Server)

Client

sio.emit('msg', 'Hi')

@sio.on('reply')
def on_reply(data):
    print('Reply:', data)

Server

@sio.event
def msg(sid, data):
    print('Received:', data)
    sio.emit('reply', 'Hello from server', to=sid)

#Java (Client then Server)

Client

socket.emit("msg", "Hi");
socket.on("reply", args -> System.out.println("Reply: " + args[0]));

Server

io.on("connection", args -> {
    var client = args[0];
    client.on("msg", msgArgs -> {
        System.out.println("Received: " + msgArgs[0]);
        client.emit("reply", "Hello from server");
    });
});

#Swift (Client then Server)

Client

socket.emit("msg", "Hi")
socket.on("reply") { data, _ in
  print("Reply:", data[0])
}

Server Server side in Swift is rare; use Node.js/Python.

#C# (Client then Server)

Client

socket.Emit("msg", "Hi");
socket.On("reply", data => Console.WriteLine("Reply: " + data));

Server

socket.OnMessage = message =>
{
    Console.WriteLine("Received: " + message);
    socket.Send("reply", "Hello from server");
};

#Go (Client then Server)

Client

socket.Emit("msg", "Hi")
socket.On("reply", func(msg string) {
    fmt.Println("Reply:", msg)
})

Server

server.OnEvent("/", "msg", func(s socketio.Conn, msg string) {
    fmt.Println("Received:", msg)
    s.Emit("reply", "Hello from server")
})

#Rust (Client then Server)

Client

socket.emit("msg", Payload::String("Hi"));
socket.on("reply", |payload| println!("Reply: {:?}", payload));

Server Experimental; typically use Node.js/Python.


#广播与房间机制 (Broadcasting & Rooms)

#Client (All Languages)

  • Join a room:

    // JavaScript/Python/C#/etc.
    socket.emit('join', 'room1');
    socket.on('msg', (data) => console.log('Room message:', data));
    

#Server (All Languages)

  • Node.js

    io.on('connection', (socket) => {
      socket.on('join', (room) => {
        socket.join(room);
        io.to(room).emit('msg', 'Hello Room');
      });
    });
    
  • Python

    @sio.event
    def join(sid, room):
        sio.enter_room(sid, room)
        sio.emit('msg', 'Hello Room', room=room)
    
  • Go

    server.OnEvent("/", "join", func(s socketio.Conn, room string) {
        s.Join(room)
        server.BroadcastToRoom("/", room, "msg", "Welcome")
    })
    

#断开连接与异常处理 (Disconnects & Errors)

#Client (All Languages)

socket.on('disconnect', (reason) => console.log('Disconnected:', reason));
socket.on('connect_error', (err) => console.error('Connection error:', err));
@sio.event
def disconnect():
    print('Disconnected')

@sio.event
def connect_error(data):
    print('Connection error:', data)
// Go client library varies; similar patterns apply.

#Server (All Languages)

io.on('connection', (socket) => {
  socket.on('disconnect', (reason) =>
    console.log('Client disconnected:', reason)
  );
});
server.OnDisconnect("/", func(s socketio.Conn, reason string) {
    fmt.Println("Client disconnected:", reason)
})

#命名空间隔离 (Namespaces)

#Client (All Languages)

const adminSocket = io('/admin');
sio.connect('http://localhost:3000/admin', namespaces=['/admin'])

#Server (All Languages)

io.of('/admin').on('connection', (socket) => {
  console.log('Admin connected:', socket.id);
});
server.Of("/admin").OnConnect(func(s socketio.Conn) {
  fmt.Println("Admin connected:", s.ID())
})

#身份验证与 Token 握手 (Authentication)

#Client (All Languages)

const socket = io('http://localhost:3000', {
  auth: { token: 'abc' }
});
sio.connect('http://localhost:3000', auth={'token': 'abc'})

#Server (All Languages)

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  token === 'abc' ? next() : next(new Error('Auth error'));
});

#调试与日志排查技巧 (Debugging & Logging)

#Client

  • Log events:

    socket.onAny((event, ...args) => console.log(event, args));
    
  • Inspect network in browser devtools.

#Server

  • JavaScript

    DEBUG=socket.io* node server.js
    
  • Python

    import logging
    logging.getLogger('socketio').setLevel(logging.DEBUG)
    
  • Go Print handler errors and use middleware for structured logs.


#⚡ 高级特性与技巧 (Advanced Features)

#Middleware

Client (Rarely needed)

Server

io.use((socket, next) => {
  console.log('Middleware:', socket.id);
  next();
});
server.Use(func(s socketio.Conn, next func()) {
  fmt.Println("Middleware triggered:", s.ID())
  next()
})

#Binary Streaming

Client

fetch('/file')
  .then((res) => res.arrayBuffer())
  .then((buf) => socket.emit('file', buf));

Server

server.OnEvent("/", "file", func(s socketio.Conn, data []byte) {
    ioutil.WriteFile("upload", data, 0644)
})

#最佳实践规范 (Best Practices)

Implement reconnection with exponential backoff on the client.

Sanitize and validate all data on both sides.

Use TLS in production and rotate authentication tokens frequently.

Separate concerns with namespaces and rooms.

Throttle high-frequency events and enable compression where possible.

Official docs: https://socket.io/docs/v4/