Vue 3 和 WebRTC 实现点对点聊天应用

Vue 3 和 WebRTC 实现点对点聊天应用

尽意
2024-11-15 / 0 评论 / 49 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年11月15日,已超过69天没有更新,若内容或图片失效,请留言反馈。
使用 Vue 3 和 WebRTC 来实现一个简单的点对点聊天应用,服务端使用 WebSocket (ws) 来建立信令服务器,用于连接和交换 WebRTC 所需的 SDP 和 ICE 候选信息。

1. 项目初始化

首先,我们创建一个基于 Vue 3 的项目:

npm init vue@latest webrtc-chat
cd webrtc-chat
npm install

然后,安装 WebSocket 依赖:

npm install ws

2. 创建 WebSocket 信令服务器

我们使用 Node.js 和 ws 模块来创建信令服务器:

// server.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  ws.on('message', (message) => {
    // 将消息广播给其他客户端
    wss.clients.forEach((client) => {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  // 向新连接的客户端发送欢迎消息
  ws.send(JSON.stringify({ type: 'welcome', message: 'Connected to WebSocket server' }));
});

console.log('WebSocket server is running on ws://localhost:8080');

运行服务器:

node server.js

3. 创建 Vue 3 应用

src 文件夹中创建 components/Chat.vue 组件。

<template>
  <div>
    <h2>点对点聊天</h2>
    <textarea v-model="message" placeholder="输入消息..."></textarea>
    <button @click="sendMessage">发送</button>
    <button @click="createOffer">发送 Offer</button>
    <div v-for="(msg, index) in messages" :key="index">{{ msg }}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
      messages: [],
      peerConnection: null,
      dataChannel: null,
      ws: null
    };
  },
  mounted() {
    this.initializeWebSocket(); // 初始化 WebSocket
    this.initializePeerConnection(); // 初始化 PeerConnection
  },
  methods: {
    // 初始化 WebSocket 连接
    initializeWebSocket() {
      this.ws = new WebSocket('ws://localhost:8080');

      // 接收来自信令服务器的消息
      this.ws.onmessage = (event) => {
        const data = JSON.parse(event.data);
        if (data.type === 'offer') {
          this.handleOffer(data); // 处理接收到的 Offer
        } else if (data.type === 'answer') {
          this.handleAnswer(data); // 处理接收到的 Answer
        } else if (data.type === 'candidate') {
          this.addIceCandidate(data); // 添加接收到的 ICE 候选
        }
      };
    },

    // 初始化 PeerConnection 和数据通道
    initializePeerConnection() {
      this.peerConnection = new RTCPeerConnection();

      // 监听 ICE 候选事件
      this.peerConnection.onicecandidate = (event) => {
        if (event.candidate) {
          this.ws.send(JSON.stringify({
            type: 'candidate',
            candidate: event.candidate
          })); // 将 ICE 候选发送到信令服务器
        }
      };

      // 创建数据通道
      this.dataChannel = this.peerConnection.createDataChannel('chat');
      this.dataChannel.onmessage = (event) => {
        this.messages.push(`Peer: ${event.data}`); // 接收消息并更新聊天记录
      };

      // 监听远程数据通道
      this.peerConnection.ondatachannel = (event) => {
        this.dataChannel = event.channel;
        this.dataChannel.onmessage = (event) => {
          this.messages.push(`Peer: ${event.data}`);
        };
      };
    },

    // 创建并发送 Offer
    async createOffer() {
      const offer = await this.peerConnection.createOffer();
      await this.peerConnection.setLocalDescription(offer);
      this.ws.send(JSON.stringify({ type: 'offer', sdp: offer })); // 发送 Offer
    },

    // 处理接收到的 Offer
    async handleOffer(data) {
      await this.peerConnection.setRemoteDescription(new RTCSessionDescription(data.sdp));
      const answer = await this.peerConnection.createAnswer();
      await this.peerConnection.setLocalDescription(answer);
      this.ws.send(JSON.stringify({ type: 'answer', sdp: answer })); // 发送 Answer
    },

    // 处理接收到的 Answer
    async handleAnswer(data) {
      await this.peerConnection.setRemoteDescription(new RTCSessionDescription(data.sdp));
    },

    // 添加接收到的 ICE 候选
    async addIceCandidate(data) {
      if (data.candidate) {
        await this.peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
      }
    },

    // 发送消息
    sendMessage() {
      if (this.dataChannel && this.message) {
        this.dataChannel.send(this.message); // 通过数据通道发送消息
        this.messages.push(`Me: ${this.message}`); // 更新本地聊天记录
        this.message = ''; // 清空输入框
      }
    }
  }
};
</script>

<style>
textarea {
  width: 100%;
  height: 100px;
  margin-bottom: 10px;
}
button {
  display: block;
  margin-bottom: 10px;
}
</style>

4. 启动应用

运行以下命令以启动 Vue 应用:

npm run dev

打开浏览器开两个窗口访问 http://localhost:3000,点击发送offer即可进行实时的点对点聊天。

3

评论 (0)

取消