2024-08-23

在Vue 3中封装一个好用的WebSocket库,可以创建一个可复用的WebSocket连接管理类。以下是一个简单的示例:




// WebSocketManager.js
import { ref } from 'vue';
 
export default class WebSocketManager {
  constructor(url) {
    this.url = url;
    this.socket = ref(null);
    this.isConnected = ref(false);
    this.connect();
  }
 
  connect() {
    this.socket.value = new WebSocket(this.url);
    this.socket.value.onopen = () => {
      this.isConnected.value = true;
      console.log('WebSocket connected');
    };
    this.socket.value.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
    this.socket.value.onmessage = (message) => {
      console.log('Received message:', message.data);
      // Handle incoming messages here
    };
    this.socket.value.onclose = () => {
      this.isConnected.value = false;
      console.log('WebSocket disconnected');
    };
  }
 
  send(message) {
    if (this.isConnected.value) {
      this.socket.value.send(message);
    } else {
      console.error('WebSocket is not connected');
    }
  }
 
  close() {
    if (this.socket.value) {
      this.socket.value.close();
    }
  }
}

使用该封装:




// main.js
import { createApp } from 'vue';
import App from './App.vue';
import WebSocketManager from './WebSocketManager';
 
const app = createApp(App);
const webSocketManager = new WebSocketManager('wss://your-websocket-url');
 
app.config.globalProperties.$webSocketManager = webSocketManager;
 
app.mount('#app');

在组件中使用:




<script setup>
import { ref } from 'vue';
 
const message = ref('');
const $webSocketManager = app.config.globalProperties.$webSocketManager;
 
function sendMessage() {
  $webSocketManager.send(message.value);
}
</script>
 
<template>
  <input v-model="message" placeholder="Type your message">
  <button @click="sendMessage">Send</button>
</template>

这个封装提供了一个简单的WebSocket管理类,它处理连接、消息发送和关闭。它也提供了一个例子,展示了如何在Vue应用中使用该封装。

2024-08-21



<template>
  <div>
    <input v-model="message" @keyup.enter="sendMessage" placeholder="输入消息">
    <button @click="sendMessage">发送</button>
    <ul>
      <li v-for="message in messages" :key="message.id">
        {{ message.content }}
      </li>
    </ul>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      message: '',
      messages: [],
      socket: null,
    };
  },
  created() {
    this.socket = new WebSocket('ws://your-websocket-server');
    this.socket.onmessage = this.handleIncomingMessage;
  },
  methods: {
    sendMessage() {
      this.socket.send(JSON.stringify({ message: this.message }));
      this.message = '';
    },
    handleIncomingMessage(event) {
      const data = JSON.parse(event.data);
      this.messages.push(data);
    }
  },
  beforeDestroy() {
    this.socket.close();
  }
};
</script>

这个简单的Vue组件展示了如何在Vue.js应用中使用WebSocket进行实时通信。它包括创建WebSocket连接、发送消息和接收消息的基本逻辑。同时,它也展示了如何在组件销毁前关闭WebSocket连接,防止内存泄漏。

2024-08-21

错误解释:

这个错误表明你在尝试使用WebSocket的send方法发送消息时出现了问题。具体来说,错误信息“Failed to execute ‘send‘ on ‘WebSocket‘: Still in”通常意味着你正在尝试发送消息,但WebSocket连接当前并未处于可以发送消息的状态。

解决方法:

  1. 检查WebSocket实例的状态:确保在调用send方法之前,WebSocket连接已经建立(即状态为OPEN)。
  2. 使用事件监听器处理状态变化:可以监听opencloseerror等事件,在合适的时候再发送消息。
  3. 错误处理:在调用send方法时,使用try-catch语句块来捕获可能的异常,并进行相应的错误处理。

示例代码:




const ws = new WebSocket('wss://your-websocket-url');
 
ws.onopen = function(event) {
  // 当WebSocket连接打开时发送消息
  ws.send('Your message here');
};
 
ws.onerror = function(event) {
  // 处理错误
  console.error('WebSocket error observed:', event);
};
 
// 如果需要在任何时候都能发送消息,可以这样做:
if (ws.readyState === WebSocket.OPEN) {
  ws.send('Your message here');
} else {
  // 连接尚未建立,等待`open`事件或处理其他状态
}

确保在ws.onopen回调函数中或者当ws.readyState等于WebSocket.OPEN时发送消息,这样可以保证WebSocket连接已经准备好接收消息。

2024-08-20

以下是一个简单的Spring Boot聊天室示例,使用WebSocket实现:




import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
 
@Controller
@RequestMapping("/chat")
public class ChatController {
 
    @GetMapping
    public ModelAndView chat() {
        return new ModelAndView("chat");
    }
}
 
@ServerEndpoint("/ws/chat")
public class ChatEndpoint {
    private static final Set<ChatEndpoint> sessions = Collections.synchronizedSet(new HashSet<>());
 
    private Session session;
 
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        sessions.add(this);
        broadcast("New user joined the chat room.");
    }
 
    @OnClose
    public void onClose() {
        sessions.remove(this);
        broadcast("A user left the chat room.");
    }
 
    @OnMessage
    public void onMessage(String message) {
        broadcast(message);
    }
 
    @OnError
    public void onError(Throwable error) {
        error.printStackTrace();
    }
 
    public void broadcast(String message) {
        for (ChatEndpoint client : sessions) {
            try {
                synchronized (client) {
                    client.session.getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个例子中,ChatController 是一个普通的Spring MVC控制器,负责处理HTTP请求并返回聊天室的页面。ChatEndpoint 使用@ServerEndpoint 注解来指定WebSocket的端点,并处理客户端的连接、关闭、消息接收和错误。

这个简单的聊天室没有数据持久化,也没有认证或授权,只是为了演示WebSocket的基本使用。在生产环境中,你需要添加安全控制、用户认证、过滤不合法的消息、处理并发等功能。

2024-08-19



<?php
// 引入WebSocket服务器类
require 'vendor/autoload.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Server\EchoServer;
require 'config.php';
 
// 创建WebSocket服务器
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new EchoServer('Hello, WebSockets!')
        )
    ),
    $webSocketsServerPort
);
 
$server->run();

这段代码使用了Ratchet库来创建一个简单的WebSocket服务器。它设置了一个监听特定端口的服务器,并且当收到客户端的WebSocket连接时,会回显接收到的消息。这个例子展示了如何使用Ratchet库快速创建一个基本的实时通信应用程序。

2024-08-19

要使用Python实现基于WebSocket的视频推流到网页,你可以使用asgi框架(如uvicorn)和websockets库。以下是一个简单的示例,演示如何将服务器端视频流发送到客户端。

首先,确保安装了必要的库:




pip install uvicorn websockets-stream

然后,创建一个ASGI应用程序来处理WebSocket连接并发送视频流:




import asyncio
from io import BytesIO
from PIL import Image
from websockets import connect, WebSocketServer, WebSocket
from websockets.server import WebSocketServerProtocol
from websockets_streaming.consumer import MediaStreamConsumer
 
async def echo(websocket: WebSocket, path: str):
    consumer = MediaStreamConsumer()
    await consumer.connect(websocket)
 
    # 假设你有一个视频源,比如视频文件或摄像头流
    # 这里我们用一个生成帧的示例来代替实际视频源
    cap = cv2.VideoCapture(0)  # 打开摄像头
    while True:
        ret, frame = cap.read()  # 从摄像头读取一帧
        if not ret:
            break
        
        # 将帧转换为JPEG格式并发送
        _, buffer = cv2.imencode('.JPEG', frame)
        jpg_image = Image.fromarray(buffer)
        byte_io = BytesIO()
        jpg_image.save(byte_io, 'JPEG')
        await consumer.send_data(byte_io.getvalue())
 
asyncio.get_event_loop().run_until_complete(
    WebSocketServer(echo, '0.0.0.0', 8765).serve_forever()
)

在客户端,你需要一个HTML页面来接收视频流并显示:




<!DOCTYPE html>
<html>
<head>
    <title>Video Stream</title>
</head>
<body>
    <img id="video-frame" src=""/>
    <script>
        var ws = new WebSocket("ws://localhost:8765");
        ws.binaryType = "arraybuffer";
        ws.onmessage = function(event) {
            if (event.data instanceof ArrayBuffer) {
                var blob = new Blob([event.data], {type: 'image/jpeg'});
                var url = URL.createObjectURL(blob);
                document.getElementById('video-frame').src = url;
            }
        };
    </script>
</body>
</html>

在服务器端运行uvicorn命令启动ASGI服务器:




uvicorn asgi:echo --reload

然后,用浏览器打开客户端的HTML页面,你应该能看到摄像头捕捉到的视频流。这个例子使用了websockets-streaming库来简化流的发送。注意,这个例子仅用于演示目的,实际应用中你需要处理错误,确保视频流的稳定性和安全性。

2024-08-19

AJAX、Axios 和 Fetch 都是用于在浏览器中执行异步 HTTP 请求的工具,但它们之间有一些关键的区别:

  1. AJAX (Asynchronous JavaScript and XML): 早期的技术,现在已经被 Fetch API 替代,但是开发者可能仍然需要了解它,因为一些旧的代码可能仍然在使用它。它使用 XMLHttpRequest 对象来发送异步请求。
  2. Axios: 是一个基于 Promise 的 HTTP 客户端,它在浏览器和 node.js 中都可以使用。它的主要特点是在 node.js 中发送 http 请求时,它会返回一个 Promise。
  3. Fetch: 是一个现代的、强大的、灵活的 API,用于发起网络请求,并且可以使用 Promise 处理请求的结果。

关于 WebSocket 通信:

WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,能够实现客户端和服务器之间的持续通信。WebSocket 通信不同于 HTTP 通信,它不需要每次都发送 HTTP 请求,因此它更高效,能够节省带宽和服务器资源。

以下是一个简单的 WebSocket 示例:

服务器端 (Node.js 使用 ws 库):




const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
 
wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
 
  ws.send('something');
});

客户端 (HTML + JavaScript):




const ws = new WebSocket('ws://localhost:8080');
 
ws.on('open', function open() {
  console.log('connected');
});
 
ws.on('close', function close() {
  console.log('disconnected');
});
 
ws.on('message', function incoming(data) {
  console.log('received: %s', data);
});

在这个例子中,服务器端创建了一个 WebSocket 服务器,监听 8080 端口的连接。当客户端连接时,服务器端打印出一个消息,并发送一个 'something' 的消息给客户端。客户端同样打印出接收到的消息。

2024-08-19



<template>
  <div>
    <!-- WebSocket 状态显示 -->
    <p>WebSocket 状态: {{ wsStatus }}</p>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      wsStatus: '连接中',
      ws: null,
      lockReconnect: false, // 防止重复连接
      timeout: 10000, // 心跳超时时间
      timeoutObj: null, // 心跳超时对象
      serverTimeoutObj: null // 服务器心跳超时对象
    };
  },
  created() {
    this.initWebSocket();
  },
  methods: {
    initWebSocket() {
      // 初始化WebSocket
      this.ws = new WebSocket('ws://your-websocket-server');
 
      this.ws.onopen = this.onOpen;
      this.ws.onmessage = this.onMessage;
      this.ws.onclose = this.onClose;
      this.ws.onerror = this.onError;
 
      // 心跳检测
      this.timeoutObj && clearTimeout(this.timeoutObj);
      this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
      this.startHeartBeat();
    },
    onOpen(event) {
      this.wsStatus = '已连接';
      // ... 其他操作
    },
    onMessage(event) {
      // 处理消息
      // ...
    },
    onClose(event) {
      this.wsStatus = '已关闭';
      // ... 其他操作
    },
    onError(event) {
      this.wsStatus = '发生错误';
      // ... 其他操作
    },
    reconnect() {
      if (this.lockReconnect) return;
      this.lockReconnect = true;
      // 没有连接上会一直重连,设置定时器防止过多重连
      this.timeoutObj && clearTimeout(this.timeoutObj);
      this.timeoutObj = setTimeout(() => {
        this.initWebSocket();
        this.lockReconnect = false;
      }, 2000);
    },
    startHeartBeat() {
      this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
      this.serverTimeoutObj = setTimeout(() => {
        // 发送心跳,服务器端如果10秒内未收到心跳,关闭连接
        this.ws.send('heartbeat');
        this.startHeartBeat();
      }, 10000);
    }
  },
  beforeDestroy() {
    this.ws.close(); // 关闭WebSocket连接
  }
};
</script>

这段代码展示了如何在Vue 2中实现一个包含心跳检测和自动重连的WebSocket模块。它使用了WebSocket实例的各种生命周期事件,并通过计时器实现了心跳的发送和检测机制。当WebSocket连接关闭时,它会尝试重新连接,并且使用了锁的机制防止过度的重连尝试。

2024-08-19



import 'package:web_socket_channel/io.dart';
 
// 定义WebSocket连接的地址
const String serverUrl = 'ws://your-websocket-server-url';
 
// 创建WebSocket连接的通道
IOWebSocketChannel channel = IOWebSocketChannel.connect(Uri.parse(serverUrl));
 
// 监听服务器发送的消息
channel.stream.listen(
  (message) {
    print('收到服务器消息: $message');
  },
  onError: (error) {
    print('WebSocket出错: $error');
  },
  onDone: () {
    print('WebSocket连接已关闭');
  },
  cancelOnError: true,
);
 
// 发送消息到服务器
channel.sink.add('你好,服务器!');
 
// 关闭WebSocket连接
channel.sink.close();

这段代码展示了如何在Flutter中使用web_socket_channel包来创建和管理WebSocket连接。它包括连接到一个WebSocket服务器,监听消息,发送消息,处理错误和关闭连接。这是一个简洁且可以直接使用的WebSocket连接封装示例。

2024-08-19



import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
 
@Component
public class NettyServer implements ApplicationListener<ContextRefreshedEvent> {
 
    private static final int PORT = 8080;
 
    @Autowired
    private WebSocketServerInitializer webSocketServerInitializer;
 
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        start();
    }
 
    public void start() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(webSocketServerInitializer);
 
            ChannelFuture f = b.bind(PORT).sync();
            System.out.println("Web socket server started at port " + PORT);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

这段代码实现了Netty服务器的启动,并在Spring容器完全刷新之后绑定到指定端口。它使用了NioEventLoopGroupNioServerSocketChannel来实现非阻塞I/O。在实际部署时,你可能需要根据实际需求对代码进行相应的调整,例如启动参数配置、安全性配置等。