WebSocket

HTML5 et WebSocket

Le protocole WebSocket a été normalisé en 2011 dans le but initial de permettre aux navigateurs de créer des connexions stables et bidirectionnelles avec un serveur. Avant cela, les navigateurs ne prenaient en charge que HTTPRequests, ce qui n’est pas bien adapté à la communication bidirectionnelle.

Le protocole est assez simple, basé sur des messages, et constitue un outil très puissant pour envoyer des notifications « push » aux navigateurs. Il a été utilisé pour mettre en place des chats, des jeux au tour par tour, etc. Il utilise toujours une connexion TCP, ce qui est bon pour la fiabilité mais pas pour la latence, donc pas bon pour les applications en temps réel comme la VoIP et les jeux rapides (voir WebRTC pour ces cas d’utilisation).

En raison de sa simplicité, de sa grande compatibilité et de sa facilité d’utilisation par rapport à une connexion TCP brute, WebSocket a rapidement commencé à se répandre en dehors des navigateurs, dans les applications natives, comme moyen de communication avec les serveurs réseau.

Godot supporte WebSocket en natif et en exportation HTML5.

Utilisation de WebSocket dans Godot

WebSocket est implémenté dans Godot via trois classes principales WebSocketClient, WebSocketServer, et WebSocketPeer. La mise en œuvre de WebSocket est compatible avec le multijoueur de haut niveau. Voir la section high-level multiplayer pour plus de détails.

Exemple de client minimal

Cet exemple vous montrera comment créer une connexion WebSocket à un serveur distant, et comment envoyer et recevoir des données.

extends Node

# The URL we will connect to
export var websocket_url = "ws://echo.websocket.org"

# Our WebSocketClient instance
var _client = WebSocketClient.new()

func _ready():
    # Connect base signals to get notified of connection open, close, and errors.
    _client.connect("connection_closed", self, "_closed")
    _client.connect("connection_error", self, "_closed")
    _client.connect("connection_established", self, "_connected")
    # This signal is emitted when not using the Multiplayer API every time
    # a full packet is received.
    # Alternatively, you could check get_peer(1).get_available_packets() in a loop.
    _client.connect("data_received", self, "_on_data")

    # Initiate connection to the given URL.
    var err = _client.connect_to_url(websocket_url)
    if err != OK:
        print("Unable to connect")
        set_process(false)

func _closed(was_clean = false):
    # was_clean will tell you if the disconnection was correctly notified
    # by the remote peer before closing the socket.
    print("Closed, clean: ", was_clean)
    set_process(false)

func _connected(proto = ""):
    # This is called on connection, "proto" will be the selected WebSocket
    # sub-protocol (which is optional)
    print("Connected with protocol: ", proto)
    # You MUST always use get_peer(1).put_packet to send data to server,
    # and not put_packet directly when not using the MultiplayerAPI.
    _client.get_peer(1).put_packet("Test packet".to_utf8())

func _on_data():
    # Print the received packet, you MUST always use get_peer(1).get_packet
    # to receive data from server, and not get_packet directly when not
    # using the MultiplayerAPI.
    print("Got data from server: ", _client.get_peer(1).get_packet().get_string_from_utf8())

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

Ceci s’affichera :

Connected with protocol:
Got data from server: Test packet

Exemple de serveur minimal

Cet exemple vous montrera comment créer un serveur WebSocket qui écoute les connexions distante, et comment envoyer et recevoir des données.

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.connect("client_connected", self, "_connected")
    _server.connect("client_disconnected", self, "_disconnected")
    _server.connect("client_close_request", self, "_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.connect("data_received", self, "_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()

Cela imprimera (lorsqu’un client se connecte) quelque chose de similaire à ceci :

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

Démonstration de chat avancée

Une démo de chat plus avancée qui utilise optionnellement l’abstraction multijoueur de niveau moyen et une démo multijoueur de haut niveau sont disponibles dans les projets de démonstration godot demo projects sous networing/websocket_chat et networing/websocket_multiplayer.