WebSocket

HTML5 与 WebSocket

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

这个协议相当简单, 基于消息, 是一个非常强大的向浏览器推送通知的工具, 已经被用来实现聊天, 回合制游戏等. 它仍使用TCP连接, 这对可靠性有好处, 但对延迟没有好处, 所以不适合实时的应用, 比如VoIP和快节奏的游戏(这些用例见 WebRTC).

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

Godot在本机和HTML5导出中都支持WebSocket.

在 Godot 中使用 WebSocket

在Godot中,WebSocket通过三个主要类来实现 WebSocketClient, WebSocketServer, 和 WebSocketPeer.WebSocket的实现与高级多人游戏兼容. 更多细节请参见 high-level multiplayer 一节.

警告

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

最小客户端示例

本示例将向您展示如何创建与远程服务器的 WebSocket 连接, 以及如何发送和接收数据.

  1. extends Node
  2. # The URL we will connect to
  3. export var websocket_url = "wss://libwebsockets.org"
  4. # Our WebSocketClient instance
  5. var _client = WebSocketClient.new()
  6. func _ready():
  7. # Connect base signals to get notified of connection open, close, and errors.
  8. _client.connect("connection_closed", self, "_closed")
  9. _client.connect("connection_error", self, "_closed")
  10. _client.connect("connection_established", self, "_connected")
  11. # This signal is emitted when not using the Multiplayer API every time
  12. # a full packet is received.
  13. # Alternatively, you could check get_peer(1).get_available_packets() in a loop.
  14. _client.connect("data_received", self, "_on_data")
  15. # Initiate connection to the given URL.
  16. var err = _client.connect_to_url(websocket_url, ["lws-mirror-protocol"])
  17. if err != OK:
  18. print("Unable to connect")
  19. set_process(false)
  20. func _closed(was_clean = false):
  21. # was_clean will tell you if the disconnection was correctly notified
  22. # by the remote peer before closing the socket.
  23. print("Closed, clean: ", was_clean)
  24. set_process(false)
  25. func _connected(proto = ""):
  26. # This is called on connection, "proto" will be the selected WebSocket
  27. # sub-protocol (which is optional)
  28. print("Connected with protocol: ", proto)
  29. # You MUST always use get_peer(1).put_packet to send data to server,
  30. # and not put_packet directly when not using the MultiplayerAPI.
  31. _client.get_peer(1).put_packet("Test packet".to_utf8())
  32. func _on_data():
  33. # Print the received packet, you MUST always use get_peer(1).get_packet
  34. # to receive data from server, and not get_packet directly when not
  35. # using the MultiplayerAPI.
  36. print("Got data from server: ", _client.get_peer(1).get_packet().get_string_from_utf8())
  37. func _process(delta):
  38. # Call this in _process or _physics_process. Data transfer, and signals
  39. # emission will only happen when calling this function.
  40. _client.poll()

这将打印:

  1. Connected with protocol:
  2. Got data from server: Test packet

最小服务器示例

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

  1. extends Node
  2. # The port we will listen to
  3. const PORT = 9080
  4. # Our WebSocketServer instance
  5. var _server = WebSocketServer.new()
  6. func _ready():
  7. # Connect base signals to get notified of new client connections,
  8. # disconnections, and disconnect requests.
  9. _server.connect("client_connected", self, "_connected")
  10. _server.connect("client_disconnected", self, "_disconnected")
  11. _server.connect("client_close_request", self, "_close_request")
  12. # This signal is emitted when not using the Multiplayer API every time a
  13. # full packet is received.
  14. # Alternatively, you could check get_peer(PEER_ID).get_available_packets()
  15. # in a loop for each connected peer.
  16. _server.connect("data_received", self, "_on_data")
  17. # Start listening on the given port.
  18. var err = _server.listen(PORT)
  19. if err != OK:
  20. print("Unable to start server")
  21. set_process(false)
  22. func _connected(id, proto):
  23. # This is called when a new peer connects, "id" will be the assigned peer id,
  24. # "proto" will be the selected WebSocket sub-protocol (which is optional)
  25. print("Client %d connected with protocol: %s" % [id, proto])
  26. func _close_request(id, code, reason):
  27. # This is called when a client notifies that it wishes to close the connection,
  28. # providing a reason string and close code.
  29. print("Client %d disconnecting with code: %d, reason: %s" % [id, code, reason])
  30. func _disconnected(id, was_clean = false):
  31. # This is called when a client disconnects, "id" will be the one of the
  32. # disconnecting client, "was_clean" will tell you if the disconnection
  33. # was correctly notified by the remote peer before closing the socket.
  34. print("Client %d disconnected, clean: %s" % [id, str(was_clean)])
  35. func _on_data(id):
  36. # Print the received packet, you MUST always use get_peer(id).get_packet to receive data,
  37. # and not get_packet directly when not using the MultiplayerAPI.
  38. var pkt = _server.get_peer(id).get_packet()
  39. print("Got data from client %d: %s ... echoing" % [id, pkt.get_string_from_utf8()])
  40. _server.get_peer(id).put_packet(pkt)
  41. func _process(delta):
  42. # Call this in _process or _physics_process.
  43. # Data transfer, and signals emission will only happen when calling this function.
  44. _server.poll()

这将打印(当客户端连接时)与此类似的东西:

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

高级聊天演示

godot demo projects 下 networking/websocket_chat 和 networking/websocket_multiplayer 有一个更高级的聊天演示demo, 可以选择使用多人中级抽象和高级多人演示demo.