[关闭]
@Pigmon 2017-10-10T09:28:03.000000Z 字数 2374 阅读 424

Unity3D 与 Python 的 Socket 通信简单指南

实习


简介

Udacity Self-driving Simulator 中,Unity 场景和 Tensorflow 是通过 Socket 进行通信的,Unity 将当前摄像头的截图以及车辆状态发送给 Tensorflow,Tensorflow 得出结果后再发回给Unity。
Unity端使用的是一个免费插件 Unity SocketIO;Python 端是 socketio 模块。

下面的例子是最简化的一个通信演示,用以备忘,或者将来有人需要熟悉其过程时可以迅速上手。

过程:
建立连接后,Server (Python 端) 发给 Client (Unity 3D) 一个数字,Client 收到后将其 +1 后发回给Server,Server 再 +1 发给 Client,如此往复。

Unity 关卡

在 Udacity 项目中新建一个 Scene 以后。

(1) 在 Udacity 项目的 Project 目录中选择 Assets - SoketIO - Prefabs,将该目录下的 SocketIO 拖入到场景中,如下图所示。
socket1.png-26.7kB

这个目录只要安装了该插件就会有。

(2) 选择刚刚拖入场景的 SocketIO,编辑其 url 属性,加入:

  1. ws://127.0.0.1:4567/socket.io/?EIO=4&transport=websocket

如下图所示:
socket2.png-27.5kB

(3) 在场景中加入一个空的 GameObject,命名为如 'TestSocket' 。并为其添加一个新脚本程序。

程序内容:

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using SocketIO;
  4. public class TestSocket2 : MonoBehaviour
  5. {
  6. // 在 Editor 里把 SocketIO 拖过来
  7. public SocketIOComponent sio;
  8. void Start()
  9. {
  10. if (sio == null)
  11. Debug.LogError("Drop a SocketIOComponent to Me!");
  12. // 声明 connect 事件和 server_sent 事件的回调函数
  13. sio.On("connect", OnConnect);
  14. sio.On("server_sent", OnReceive);
  15. }
  16. /// <summary>
  17. /// connect 事件的回调函数
  18. /// </summary>
  19. /// <param name="obj"></param>
  20. void OnConnect(SocketIOEvent obj)
  21. {
  22. Debug.Log("Connection Open");
  23. OnReceive(obj);
  24. }
  25. /// <summary>
  26. /// 接收到 server_sent 事件的回调函数
  27. /// </summary>
  28. /// <param name="obj">SocketIOEvent</param>
  29. void OnReceive(SocketIOEvent obj)
  30. {
  31. // 1. 接收并输出 Server 传递过来的数字
  32. JSONObject jsonObject = obj.data;
  33. string rcv_nbr = jsonObject.GetField("nbr").str;
  34. Debug.Log("Recieved From Server : " + rcv_nbr);
  35. // 2. 将数字 +1 并返回给 Server
  36. try
  37. {
  38. int int_nbr = int.Parse(rcv_nbr);
  39. SendToServer(int_nbr + 1);
  40. }
  41. catch
  42. {
  43. }
  44. }
  45. /// <summary>
  46. /// 将数字发给 Server
  47. /// </summary>
  48. /// <param name="_nbr">发送的数字</param>
  49. void SendToServer(int _nbr)
  50. {
  51. Dictionary<string, string> data = new Dictionary<string, string>();
  52. data["nbr"] = _nbr.ToString();
  53. sio.Emit("client_sent", new JSONObject(data));
  54. }
  55. }

(4) 将 SocketIO 拖入到 TestSocket 的 sio 属性中。
完成后 TestSocket 的属性如下图所示:
socket3.png-43.6kB

Server 端 Python 程序

  1. import socketio
  2. import eventlet
  3. import eventlet.wsgi
  4. from flask import Flask
  5. sio = socketio.Server()
  6. app = Flask(__name__)
  7. # "连接建立的回调函数"
  8. @sio.on('connect')
  9. def on_connect(sid, environ):
  10. print("connect ", sid)
  11. send_to_client(101)
  12. # "接收 Client 事件 (client_sent) 的回调函数"
  13. @sio.on('client_sent')
  14. def on_revieve(sid, data):
  15. if data:
  16. print ('From Client : %s' % data['nbr'])
  17. send_to_client(int(data['nbr']) + 1)
  18. else:
  19. print ('Recieved Empty Data!')
  20. # "向 Client 发送数字"
  21. def send_to_client(_nbr):
  22. sio.emit(
  23. 'server_sent',
  24. data = {'nbr':_nbr.__str__()},
  25. skip_sid=True)
  26. if __name__ == '__main__':
  27. app = socketio.Middleware(sio, app)
  28. eventlet.wsgi.server(eventlet.listen(('', 4567)), app)

执行

先运行 Python 程序,再运行 Unity 的场景。

可以看到服务器端和客户端的输出如下:
socket4.png-4.4kB

socket5.png-34.3kB

这样即代表运行成功。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注