2024-08-23

WebSocket 是 HTML5 引入的一种在单个 TCP 连接上进行全双工通讯的协议。可以在客户端和服务器之间进行快速的双向通信。

以下是一个使用JavaScript创建WebSocket服务器连接的例子:




// 检查浏览器是否支持WebSocket
if (window.WebSocket) {
    // 创建一个新的WebSocket实例
    var ws = new WebSocket('ws://localhost:8080');
 
    // 当WebSocket打开时触发
    ws.onopen = function(event) {
        console.log('WebSocket 连接已打开');
    };
 
    // 当WebSocket接收到服务器发送的消息时触发
    ws.onmessage = function(event) {
        console.log('收到消息: ' + event.data);
    };
 
    // 当WebSocket关闭时触发
    ws.onclose = function(event) {
        console.log('WebSocket 连接已关闭');
    };
 
    // 当WebSocket通信发生错误时触发
    ws.onerror = function(error) {
        console.log('WebSocket 出现错误: ' + error);
    };
 
    // 使用WebSocket发送消息
    function sendMessage(message) {
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(message);
        } else {
            console.log('WebSocket 连接没有打开');
        }
    }
 
    // 示例:发送消息给服务器
    sendMessage('Hello, Server!');
} else {
    console.log('浏览器不支持WebSocket');
}

在上述代码中,我们首先检查浏览器是否支持WebSocket。如果支持,我们创建一个新的WebSocket实例,指定服务器的URL。然后,我们定义了几个事件处理程序来处理不同的WebSocket生命周期事件。我们还定义了一个函数sendMessage来发送消息给服务器。

服务器端的实现会依据你使用的编程语言和WebSocket库而有所不同。以下是一个使用Node.js和ws库的简单服务器端示例:




const WebSocket = require('ws');
 
// 创建WebSocket服务器实例
const wss = new WebSocket.Server({ port: 8080 });
 
// 当客户端连接时触发
wss.on('connection', function connection(ws) {
    console.log('新客户端已连接');
 
    // 当接收到客户端发送的消息时触发
    ws.on('message', function incoming(message) {
        console.log('收到消息: %s', message);
 
        // 将消息发送回客户端
        ws.send('你发送的消息已接收: ' + message);
    });
 
    // 当客户端断开连接时触发
    ws.on('close', function close() {
        console.log('客户端已断开连接');
    });
 
    // 当出现错误时触发
    ws.on('error', function error(error) {
        console.log('发生错误: %s', error);
    });
});
 
console.log('WebSocket服务器运行在 ws://localhost:8080');

在服务器端,我们创建了一个WebSocket服务器实例,并监听连接事件。当客户端连接时,我们可以接收它发送的消息,并将响应发回给客户端。这个简单的服务器实现可以根据实际需求扩展,比如处理认证、路由消息到不同的客户端、记录消息等。

2024-08-23

WebSocket和AJAX(Asynchronous JavaScript and XML)都是用于在浏览器和服务器之间进行数据交换的技术,但它们有不同的应用场景和工作方式。

  1. AJAX:

    • 应用场景:AJAX主要用于在不刷新页面的情况下更新网页的部分内容。
    • 工作方式:AJAX使用HTTP长轮询(long polling)或流(HTTP streaming)来实现服务器向客户端发送数据的推送功能。
    • 优点:AJAX可以异步发送请求,不会阻塞用户的其他操作。
    • 缺点:需要频繁地发送请求以获取最新数据,对服务器和带宽资源的消耗较大。
  2. WebSocket:

    • 应用场景:WebSocket是一个全双工通信协议,用于在客户端和服务器之间建立一个持久的连接,以实现双向实时通信。
    • 工作方式:WebSocket通过一次HTTP握手(handshake)建立连接,之后服务器和客户端可以互相发送消息,不需要重新建立连接。
    • 优点:实现了真正的实时通信,减少了服务器和带宽资源的消耗。
    • 缺点:需要服务器端支持。

以下是使用WebSocket和AJAX的简单示例:

AJAX轮询示例:




function pollData() {
    $.ajax({
        url: 'https://example.com/data',
        success: function(data) {
            // 处理数据
            console.log(data);
            // 继续进行下一轮请求
            setTimeout(pollData, 3000);
        },
        error: function() {
            // 处理错误
            console.log('Error fetching data');
            // 重试
            setTimeout(pollData, 3000);
        }
    });
}
// 初始化轮询
pollData();

WebSocket示例:




var ws = new WebSocket('ws://example.com/socket');
 
ws.onopen = function() {
    console.log('WebSocket connected');
};
 
ws.onmessage = function(event) {
    // 处理服务器发送的数据
    console.log(event.data);
};
 
ws.onerror = function(error) {
    // 处理错误
    console.log('WebSocket error: ' + error);
};
 
ws.onclose = function() {
    console.log('WebSocket disconnected');
};

在选择使用WebSocket还是AJAX时,需要考虑实际需求和目标系统的支持情况。对于实时通信和需要较少更新内容的应用,推荐使用WebSocket。而对于不需要实时更新,或者需要兼容不支持WebSocket的老旧浏览器的应用,可以使用AJAX长轮询作为替代方案。

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连接关闭时,它会尝试重新连接,并且使用了锁的机制防止过度的重连尝试。