WebSocket

HTML5およびWebSocket

The WebSocket protocol was standardized in 2011 with the original goal of allowing browsers to create stable and bidirectional connections with a server. Before that, browsers used to only support HTTPRequests, which is not well-suited for bidirectional communication.

プロトコルは非常にシンプルで、メッセージベースであり、ブラウザにプッシュ通知を送信するための非常に強力なツールであり、チャット、ターンベースのゲームなどを実装するために使用されています。遅延のため、VoIPやテンポの速いゲームなどのリアルタイムアプリケーションには適していません(これらのユースケースについては、WebRTC を参照してください)。

そのシンプルさ、幅広い互換性、および生のTCP接続より使いやすいため、WebSocketは、ネットワークサーバーと通信するための手段として、ブラウザ以外のネイティブアプリケーションですぐに広がり始めました。

Godotは、ネイティブエクスポートとHTML5エクスポートの両方でWebSocketをサポートしています。

GodotでWebソケットを使う

WebSocketは、3つのメインクラス WebSocketClientWebSocketServer および WebSocketPeer を介してGodotに実装されます。WebSocket実装は、High Level Multiplayerと互換性があります。詳細については、high-level multiplayer のセクションを参照してください。

最小限のクライアントの例

この例では、リモートサーバーへのWebSocket接続を作成する方法と、データを送受信する方法を示します。

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()

これは次のように出力されます:

Connected with protocol:
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.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()

これは(クライアントが接続したときに)次のようなものを出力します:

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

高度なチャットデモ

オプションとして、マルチプレイヤーの中レベルの抽象化とハイレベルマルチプレイヤーデモを使用するより高度なチャットデモは、networking/websocket_chatnetworking/websocket_multiplayer 内の `godot demo projects <https://github.com/godotengine/godot-demo-projects> `_ にあります。