Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

使用 WebSocket

HTML5 与 WebSocket

WebSocket 协议在 2011 年被标准化,最初的目标是让浏览器与服务器建立稳定的双向连接。在此之前,浏览器只支持 HTTP 请求,而这并不适合双向通信。

该协议是基于消息的,是一种可向浏览器发送推送通知的非常强大的工具,并且已经被用于实现聊天、回合制游戏等。它仍然使用 TCP 连接,这对可靠性有好处,但对延迟不利,因此不适合实时应用,如 VoIP 和快节奏的游戏(有关这些用例,请参阅 WebRTC)。

由于其简单性、广泛的兼容性以及比原始 TCP 连接更容易使用,WebSocket 很快就开始在浏览器之外的地方应用,在原生应用程序中作为与网络服务器通信的一种手段。

Godot 在原生导出和 Web 导出中都支持 WebSocket。

在 Godot 中使用 WebSocket

在 Godot 中,WebSocket 通过 WebSocketPeer 实现。WebSocket 实现与高阶多人游戏兼容。有关更多详细信息,请参阅《高阶多人游戏》章节。

警告

导出到 Android 时,在导出项目或使用一键部署之前,确保在 Android 导出预设中启用 INTERNET 权限。否则,Android 系统会阻止该程序的任何网络通信。

最小客户端示例

这个示例演示的是如何建立与远程服务器的 WebSocket 连接,以及如何收发数据。

extends Node

# The URL we will connect to.
# Use "ws://localhost:9080" if testing with the minimal server example below.
# `wss://` is used for secure connections,
# while `ws://` is used for plain text (insecure) connections.
@export var websocket_url = "wss://echo.websocket.org"

# Our WebSocketClient instance.
var socket = WebSocketPeer.new()


func _ready():
    # Initiate connection to the given URL.
    var err = socket.connect_to_url(websocket_url)
    if err == OK:
        print("Connecting to %s..." % websocket_url)
        # Wait for the socket to connect.
        await get_tree().create_timer(2).timeout

        # Send data.
        print("> Sending test packet.")
        socket.send_text("Test packet")
    else:
        push_error("Unable to connect.")
        set_process(false)


func _process(_delta):
    # Call this in `_process()` or `_physics_process()`.
    # Data transfer and state updates will only happen when calling this function.
    socket.poll()

    # get_ready_state() tells you what state the socket is in.
    var state = socket.get_ready_state()

    # `WebSocketPeer.STATE_OPEN` means the socket is connected and ready
    # to send and receive data.
    if state == WebSocketPeer.STATE_OPEN:
        while socket.get_available_packet_count():
            var packet = socket.get_packet()
            if socket.was_string_packet():
                var packet_text = packet.get_string_from_utf8()
                print("< Got text data from server: %s" % packet_text)
            else:
                print("< Got binary data from server: %d bytes" % packet.size())

    # `WebSocketPeer.STATE_CLOSING` means the socket is closing.
    # It is important to keep polling for a clean close.
    elif state == WebSocketPeer.STATE_CLOSING:
        pass

    # `WebSocketPeer.STATE_CLOSED` means the connection has fully closed.
    # It is now safe to stop polling.
    elif state == WebSocketPeer.STATE_CLOSED:
        # The code will be `-1` if the disconnection was not properly notified by the remote peer.
        var code = socket.get_close_code()
        print("WebSocket closed with code: %d. Clean: %s" % [code, code != -1])
        set_process(false) # Stop processing.

这个示例会打印类似这样的内容:

Connecting to wss://echo.websocket.org...
< Got text data from server: Request served by 7811941c69e658
> Sending test packet.
< Got text data from server: Test packet

最小服务器示例

这个例子将告诉你如何创建一个监听远程连接的WebSocket服务器,以及如何发送和接收数据。

extends Node

# The port we will listen to.
const PORT = 9080

# Our TCP Server instance.
var _tcp_server = TCPServer.new()

# Our connected peers list.
var _peers: Dictionary[int, WebSocketPeer] = {}

var last_peer_id := 1


func _ready():
    # Start listening on the given port.
    var err = _tcp_server.listen(PORT)
    if err == OK:
        print("Server started.")
    else:
        push_error("Unable to start server.")
        set_process(false)


func _process(_delta):
    while _tcp_server.is_connection_available():
        last_peer_id += 1
        print("+ Peer %d connected." % last_peer_id)
        var ws = WebSocketPeer.new()
        ws.accept_stream(_tcp_server.take_connection())
        _peers[last_peer_id] = ws

    # Iterate over all connected peers using "keys()" so we can erase in the loop
    for peer_id in _peers.keys():
        var peer = _peers[peer_id]

        peer.poll()

        var peer_state = peer.get_ready_state()
        if peer_state == WebSocketPeer.STATE_OPEN:
            while peer.get_available_packet_count():
                var packet = peer.get_packet()
                if peer.was_string_packet():
                    var packet_text = packet.get_string_from_utf8()
                    print("< Got text data from peer %d: %s ... echoing" % [peer_id, packet_text])
                    # Echo the packet back.
                    peer.send_text(packet_text)
                else:
                    print("< Got binary data from peer %d: %d ... echoing" % [peer_id, packet.size()])
                    # Echo the packet back.
                    peer.send(packet)
        elif peer_state == WebSocketPeer.STATE_CLOSED:
            # Remove the disconnected peer.
            _peers.erase(peer_id)
            var code = peer.get_close_code()
            var reason = peer.get_close_reason()
            print("- Peer %s closed with code: %d, reason %s. Clean: %s" % [peer_id, code, reason, code != -1])

当客户端连接时,这将打印出类似这样的内容:

Server started.
+ Peer 2 connected.
< Got text data from peer 2: Test packet ... echoing

高级聊天演示

godot demo projectsnetworking/websocket_chatnetworking/websocket_multiplayer 中有一个更高级的聊天演示,可以选择使用多人游戏中阶抽象,还有一个高阶多人游戏演示。