created at 2025-11-15 07:13,updated at 2025-11-15 08:59

官方文档:https://socket.io/zh-CN/docs/v4/server-socket-instance/

① 客户端 通过 socket.emit("key1", input.value) 发送表单内容
↓  
② 服务器端 通过 socket.on('key1', (引数) => { DB 或者其他处理 } ) 接收内容

③ 服务器端 通过 io.emit('key2', 内容); 发送内容

④ 客户端 通过 socket.on("key2", (引数) => { 画面处理 } ) 接收内容

socket.id

// server-side
io.on("connection", (socket) => {
  console.log(socket.id); // ojIckSD2jqNzOqIrAGzL   //此标识符与客户端的值同步。
});

// client-side
socket.on("connect", () => {
  console.log(socket.id); // ojIckSD2jqNzOqIrAGzL   //此标识符与客户端的值同步。
});

Socket#handshake

使用方法:const clinet_ip = socket.handshake.address;

{
  headers: /* the headers of the initial request */
  query: /* the query params of the initial request */
  auth: /* the authentication payload */
  time: /* the date of creation (as string) */
  issued: /* the date of creation (unix timestamp) */
  url: /* the request URL string */
  address: /* the ip of the client */
  xdomain: /* whether the connection is cross-domain */
  secure: /* whether the connection is secure */
}

服务器端:

import express from "express";          //导入express
import { createServer } from "http";
import { Server } from "socket.io";  //导入socket.io

const app = express();
const httpServer = createServer(app);  //?为什么要过一层原生http的createServer?
const io = new Server(httpServer);    // 生成io

io.on('connection', (socket)=> {  //开启io监听

    socket.on('key1', (msg)=>{   // 接收内容、第1引数の「key1」,同「客户端」一致
        io.emit('key2', msg);        // 发送内容、第1引数の「key2」,同「客户端」一致
    });

});

// 通过路由返回一个html
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

客户端:

<script src="/socket.io/socket.io.js"></script>  // 导入socket.io

    let socket = io();    //开启socket 

    form.addEventListener("click", function (e) {
      e.preventDefault();
      if (input.value) {
        socket.emit("key1", input.value);  // 发送内容、第1引数の「key1」,同「服务器端」一致
        input.value = "";  // 发送结束后,清空输入框
      }
    });
    
    socket.on("key2", function (引数) {  // 接收内容、第1引数の「key2」,同「服务器端」一致
   接收内容,设置Dom,innerHTML
    });

完整例:
server.js

import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";
import { DatabaseSync } from 'node:sqlite';

const __dirname = import.meta.dirname;
const __filename = import.meta.filename;

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer);

const db = new DatabaseSync(__dirname + '/chat.db');
db.exec(`
  CREATE TABLE IF NOT EXISTS messages (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      client_ip TEXT,
      msg TEXT
  );
`);


app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
  let ip = socket.handshake.address;
  console.log(socket.handshake);
  console.log(socket.id);
  socket.on('chat message', async (msg) => {
    try {
      const insert = db.prepare('INSERT INTO messages (client_ip,msg) VALUES (?, ?)');
      insert.run(ip, msg);
      io.emit('chat message', ip, msg);
    } catch (e) {
      console.error(e);
    }
  });

  socket.on('history', async () => {
    let result;
    try {
      result = db.prepare('select * from messages ORDER BY id');
      io.emit('history', result.all());
    } catch (e) {
      console.error(e);
    }
  });
});

// 在这里 app.listen(3000)将不起作用,因为它创建一个新的 HTTP 服务器。
httpServer.listen(3000, () => {
  console.log('server running at http://localhost:3000');
});

client.html

<!DOCTYPE html>
<html>

<head>
  <title>chatapp tutorial</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    }

    .display {
      top: 0;
      left: 0;
      width: 100%;
      height: calc(100vh - 60px);
      display: flex;
      flex-direction: row;
      /*border: 1px solid white;*/
    }

    #msg-list {
      flex: 5;
      list-style-type: none;
      overflow: auto;
    }

    #msg-list>li {
      padding: 0.5rem 1rem;
    }

    #msg-list>li:nth-child(odd) {
      background: rgb(207, 216, 248);
    }

    #history-list {
      margin: 0 20px 10px 10px;
      flex: 2;
      list-style-type: none;
      background-color: #4e8357;
      border: 1px solid white;
      box-shadow: 5px 5px 5px black;
      overflow: auto;
    }

    #history-list>li {
      padding: 0.5rem 1rem;
      white-space: nowrap;
    }


    #form {
      position: fixed;
      display: flex;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 60px;
      backdrop-filter: blur(10px);
      background: #181818dc;
      padding: 0.25rem;
    }

    #input {
      border: none;
      padding: 0 1rem;
      flex-grow: 1;
      margin: 0.25rem;
    }

    #input:focus {
      outline: none;
    }

    #form>button {
      background: #4e8357;
      border: none;
      padding: 0 1rem;
      margin: 0.25rem;
      border-radius: 5px;
      outline: none;
      color: #fff;
      width: 100px;
    }

    #form>button:hover {
      background-color: #07e62c;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="display">
    <ul id="msg-list"></ul>
    <ul id="history-list"></ul>
  </div>

  <form id="form" action="">
    <input id="input" autocomplete="off" />
    <button>Send</button>
    <button id="toggle-btn">Disconnect</button>
    <button id="history-btn">History</button>
  </form>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    let socket = io();

    const form = document.getElementById("form");
    const input = document.getElementById("input");
    const msgList = document.getElementById("msg-list");
    const toggleButton = document.getElementById('toggle-btn');
    const historyList = document.getElementById("history-list");
    const historyButton = document.getElementById('history-btn');

    toggleButton.addEventListener('click', (e) => {
      e.preventDefault();
      if (socket.connected) {
        toggleButton.innerText = 'Connect';
        socket.disconnect();
      } else {
        toggleButton.innerText = 'Disconnect';
        socket.connect();
      }
    });

    form.addEventListener("submit", function (e) {
      e.preventDefault();
      if (input.value) {
        socket.emit("chat message", input.value);
        input.value = "";
      }
    });

    historyButton.addEventListener('click', (e) => {
      e.preventDefault();
      if (socket.connected) {
        socket.emit("history");
      }
    });

    socket.on("chat message", function (ip, msg) {
      let item = document.createElement("li");
      item.textContent = `(${ip}) >> ${msg}`;
      msgList.appendChild(item);
      window.scrollTo(0, document.body.scrollHeight);
    });

    socket.on("history", function (result) {
      historyList.innerHTML = "";
      result.forEach(value => {
        historyList.innerHTML += `<li>${value.id} ${value.client_ip} ${value.msg}</li>`;
      });
      window.scrollTo(0, document.body.scrollHeight);
    });

  </script>
</body>

</html>
❤️ 转载文章请注明出处,谢谢!❤️