Использование WebSockets
HTML5 и WebSocket
Протокол WebSocket был стандартизирован в 2011 году с первоначальной целью — позволить браузерам создавать стабильные двунаправленные соединения с сервером. До этого браузеры поддерживали только HTTP-запросы, которые плохо подходили для двунаправленной связи.
Этот протокол основан на сообщениях и представляет собой очень мощный инструмент для отправки push-уведомлений в браузеры. Он использовался для реализации чатов, пошаговых игр и многого другого. Он по-прежнему использует TCP-соединение, что обеспечивает надёжность, но не уменьшает задержку, поэтому не подходит для приложений реального времени, таких как VoIP и динамичные игры (см. WebRTC для получения информации об этих вариантах использования).
Благодаря своей простоте, широкой совместимости и простоте использования по сравнению с обычным TCP-соединением, WebSocket начал распространяться за пределами браузеров, в собственных приложениях как средство связи с сетевыми серверами.
Godot поддерживает WebSocket как при нативном, так и при веб-экспорте.
WebSocket в контексте Godot
WebSocket реализован в Godot через WebSocketPeer. Эта реализация совместима с высокоуровневой многопользовательской системой. Подробнее см. раздел high-level multiplayer.
Предупреждение
При экспорте под Android обязательно включите разрешение INTERNET в пресете экспорта Android до экспорта проекта или использования одноразвёртывания. Иначе любое сетевое взаимодействие будет заблокировано системой 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 по путям networking/websocket_chat и networking/websocket_multiplayer.