Work in progress

The content of this page was not yet updated for Godot 4.4 and may be outdated. If you know how to improve this page or you can confirm that it's up to date, feel free to open a pull request.

WebSocket

HTML5 и WebSocket

Протокол WebSocket был стандартизирован в 2011 году с первоначальной целью позволить браузерам создавать стабильные двусторонние соединения с сервером. До этого браузеры поддерживали только HTTP-запросы, что плохо подходит для двусторонней коммуникации.

Протокол основан на сообщениях и является мощным инструментом для отправки push-уведомлений в браузеры. Он используется в чатах, пошаговых играх и т.д. WebSocket сохраняет TCP-соединение, что обеспечивает надёжность, но не снижает задержки, поэтому не подходит для приложений реального времени вроде VoIP и динамичных игр (для таких случаев см. WebRTC).

Благодаря простоте, широкой совместимости и удобству использования (по сравнению с прямыми TCP-соединениями), WebSocket быстро вышел за пределы браузеров и стал применяться в нативных приложениях для взаимодействия с сетевыми серверами.

Godot поддерживает WebSocket и в нативных в HTML5 экспортах.

WebSocket в контексте Godot

WebSocket реализован в Godot через WebSocketPeer. Эта реализация совместима с высокоуровневой многопользовательской системой. Подробнее см. раздел high-level multiplayer.

Предупреждение

При экспорте под Android обязательно включите разрешение INTERNET в пресете экспорта Android до экспорта проекта или использования одноразвёртывания. Иначе любое сетевое взаимодействие будет заблокировано системой Android.

Простой пример клиента

Этот пример покажет, как соединить WebSocket с удаленным сервером и как отправлять/получать данные.

extends Node

# The URL we will connect to.
@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("Unable to connect")
        set_process(false)
    else:
        # Wait for the socket to connect.
        await get_tree().create_timer(2).timeout

        # Send data.
        socket.send_text("Test packet")

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():
            print("Got data from server: ", socket.get_packet().get_string_from_utf8())

    # 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.

Вывод будет примерно таким:

Got data from server: Request served by 7811941c69e658
Got data from server: Test packet

Простой пример сервера

Этот пример покажет, как создать WebSocket сервер, который будет прослушивать удаленные подключения, и то, как отправлять и получать таким образом данные.

extends Node

# The port we will listen to
const PORT = 9080
# Our WebSocketServer instance
var _server = WebSocketServer.new()

func _ready():
    # Connect base signals to get notified of new client connections,
    # disconnections, and disconnect requests.
    _server.client_connected.connect(_connected)
    _server.client_disconnected.connect(_disconnected)
    _server.client_close_request.connect(_close_request)
    # This signal is emitted when not using the Multiplayer API every time a
    # full packet is received.
    # Alternatively, you could check get_peer(PEER_ID).get_available_packets()
    # in a loop for each connected peer.
    _server.data_received.connect(_on_data)
    # Start listening on the given port.
    var err = _server.listen(PORT)
    if err != OK:
        print("Unable to start server")
        set_process(false)

func _connected(id, proto):
    # This is called when a new peer connects, "id" will be the assigned peer id,
    # "proto" will be the selected WebSocket sub-protocol (which is optional)
    print("Client %d connected with protocol: %s" % [id, proto])

func _close_request(id, code, reason):
    # This is called when a client notifies that it wishes to close the connection,
    # providing a reason string and close code.
    print("Client %d disconnecting with code: %d, reason: %s" % [id, code, reason])

func _disconnected(id, was_clean = false):
    # This is called when a client disconnects, "id" will be the one of the
    # disconnecting client, "was_clean" will tell you if the disconnection
    # was correctly notified by the remote peer before closing the socket.
    print("Client %d disconnected, clean: %s" % [id, str(was_clean)])

func _on_data(id):
    # Print the received packet, you MUST always use get_peer(id).get_packet to receive data,
    # and not get_packet directly when not using the MultiplayerAPI.
    var pkt = _server.get_peer(id).get_packet()
    print("Got data from client %d: %s ... echoing" % [id, pkt.get_string_from_utf8()])
    _server.get_peer(id).put_packet(pkt)

func _process(delta):
    # Call this in _process or _physics_process.
    # Data transfer, and signals emission will only happen when calling this function.
    _server.poll()

Когда клиент подключится, в консоли появится похожая запись:

Client 1348090059 connected with protocol: selected-protocol
Got data from client 1348090059: Test packet ... echoing

Продвинутое чат-демо

Более продвинутое чат-демо с опциональным использованием абстракции среднего уровня для мультиплеера, а также демо высокоуровневого мультиплеера доступны в демо-проектах Godot по путям networking/websocket_chat и networking/websocket_multiplayer.