2024-08-23

以下是一个简单的Go语言实现的websocket服务器和两个连接到该服务器的websocket客户端的示例代码。

服务器端代码 (server.go):




package main
 
import (
    "fmt"
    "net/url"
    "os"
 
    "github.com/gorilla/websocket"
)
 
var socket = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true // 允许跨域请求
    },
}
 
func echo(w http.ResponseWriter, r *http.Request) {
    conn, _, err := socket.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer conn.Close()
 
    for {
        messageType, p, err := conn.ReadMessage()
        if err != nil {
            fmt.Println(err)
            return
        }
 
        err = conn.WriteMessage(messageType, p)
        if err != nil {
            fmt.Println(err)
            return
        }
    }
}
 
func main() {
    http.HandleFunc("/echo", echo)
    fmt.Println("Starting server on :8080")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("ListenAndServe:", err)
        os.Exit(1)
    }
}

客户端A代码 (clientA.go):




package main
 
import (
    "fmt"
    "log"
    "net/url"
    "os"
    "github.com/gorilla/websocket"
)
 
var socket = websocket.Dialer{
    Subprotocols:    []string{"p1", "p2"},
    HandshakeTimeout: 4500 * time.Millisecond,
}
 
func main() {
    u := url.URL{Scheme: "ws", Host: "localhost:8080", Path: "/echo"}
    conn, _, err := socket.Dial(u.String(), nil)
    if err != nil {
        log.Fatal("dial:", err)
    }
    defer conn.Close()
    done := make(chan struct{})
 
    go func() {
        defer close(done)
        for {
            _, message, err := conn.ReadMessage()
            if err != nil {
                log.Println("read:", err)
                return
            }
            fmt.Println("recv:", string(message))
        }
    }()
 
    for {
        message := "Hello, Client A!"
        err = conn.WriteMessage(websocket.TextMessage, []byte(message))
        if err != nil {
            log.Println("write:", err)
            return
        }
        fmt.Println("send:", message)
    }
}

客户端B的代码类似于客户端A,只是连接到服务器的路径不同,并且在发送和接收消息时,消息内容会有所区别。

确保先运行服务器 (go run server.go),然后分别运行客户端A和客户端B (go run clientA.go)。

这个简单的例子展示了如何使用gorilla/websocket包在Go中实现一个基本的websocket服务器和两个连接到该服务器的客户端。服务器端使用Upgrader来升级HTTP连接到websocket连接,并在新的websocket连接上进入循环,不断地读取消息并回送。客户端代码使用Dialer来连接到服务器并发送消息,同时接收并打印服务器

2024-08-23

在PHP中使用Workerman实现WebSocket并解决卡顿、阻塞问题,可以通过启用多进程或多线程来提高性能。以下是一个使用Workerman实现WebSocket并采用多线程的简单示例:

首先,确保你已经安装了Workerman和PHP的socket扩展。




composer require workerman/workerman
composer require workerman/websocket

然后,创建一个WebSocket服务器并启用多线程模式:




use Workerman\Worker;
 
// 注意: 确保workerman.php在项目根目录
require_once __DIR__ . '/vendor/autoload.php';
 
$worker = new Worker('websocket://0.0.0.0:2346');
 
// 开启多线程
$worker->count = 4; // 根据CPU核心数来设置,或者设置为1表示禁用多线程
 
// 设置事件回调函数
$worker->onMessage = function($connection, $data) {
    // 处理接收到的数据
    $connection->send('receive success');
};
 
Worker::runAll();

在这个例子中,$worker->count 被设置为4,表示启动4个worker进程,每个进程将以多线程方式运行。每个线程将处理来自客户端的连接和数据。这样可以有效地提高WebSocket服务的并发处理能力,减少卡顿或阻塞的问题。

请注意,在实际部署时,你可能需要进一步配置worker的数量、监听端口、SSL/TLS设置等,以及处理连接的安全性、稳定性和性能要求。

2024-08-23



// 引入WebSocket模块
const WebSocket = require('ws');
 
// 创建WebSocket服务器实例,监听端口3000
const wss = new WebSocket.Server({ port: 3000 });
 
wss.on('connection', function connection(ws) {
  // 当服务器接收到客户端消息时
  ws.on('message', function incoming(data) {
    // 解析接收到的二进制数据
    const buffer = Buffer.from(data);
    // 假设前4个字节为整数,表示后续数据长度
    const lengthBuffer = buffer.slice(0, 4);
    const dataLength = lengthBuffer.readInt32BE(0);
    // 获取实际数据
    const actualData = buffer.slice(4, 4 + dataLength);
 
    // 打印实际数据
    console.log(actualData.toString());
 
    // 回复客户端消息,这里仅为示例,实际应用中可能需要根据实际数据内容进行处理
    ws.send(JSON.stringify({ message: '收到消息,内容为:' + actualData.toString() }), (error) => {
      if (error) {
        console.error('发送消息失败', error);
      }
    });
  });
});
 
console.log('WebSocket服务器运行在 ws://localhost:3000');

这段代码创建了一个WebSocket服务器,监听3000端口。当客户端连接到服务器时,服务器解析接收到的二进制数据,并打印出解析后的字符串信息。然后,服务器向客户端发送一个JSON格式的确认消息。这个例子演示了如何处理和发送二进制数据,并且如何在WebSocket服务器中使用Buffer对象来处理二进制数据。

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库快速创建一个基本的实时通信应用程序。