python&unity3d:Websocket 稳定性
Posted
技术标签:
【中文标题】python&unity3d:Websocket 稳定性【英文标题】:python&unity3d: Websocket stability 【发布时间】:2018-04-23 10:45:45 【问题描述】:我正在 Unity3d 中创建一个与 python 的 websockets 库通信的应用程序。我的python脚本如下:
from __future__ import division
import asyncio
import websockets
import time
import os
from threading import Thread
from random import randint
from read import CustOPCLib
import socket
from jsonsocket import Client,Server
class SubHandler(object):
def data_change(self, handle, node, val, attr):
print("Python: New data change event", handle, node, val, attr)
def datachange_notification(self, node, val, data):
print("Data received: ",val)
def event(self, handle, event):
print("Python: New event", handle, event)
p = CustOPCLib()
async def hello(websocket, path):
p.connect() #my own custom library
while True:
datastring = p.opcjson() #this is a jsonstring
await websocket.send(datastring)
#print("> ".format(datastring))
time.sleep(1)
if __name__ == '__main__':
start_server = websockets.serve(hello, '127.0.0.1', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
我的json字符串如下:
"Index": 709953575,
"Moto": true,
"Start": false,
"StartWINCC": false,
"Stop": false,
"StopWINCC": false,
"Tag1": true,
"Tag2": false
这是我要发送给 Unity 的字符串。在 Unity3d 中,我制作了以下使用单声道并发队列的脚本。该脚本相应地工作,但是我遇到的问题是我从 websocket 获得了很多空值。 我的 Unity3d 脚本:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading;
public class ConcurrentQueue<T> : IEnumerable<T>, ICollection, ISerializable, IDeserializationCallback
class Node
public T Value;
public Node Next;
Node _head = new Node();
Node _tail;
int _count;
/// <summary>
/// </summary>
public ConcurrentQueue()
_tail = _head;
public ConcurrentQueue(IEnumerable<T> enumerable)
: this()
foreach (T item in enumerable)
Enqueue(item);
public void Enqueue(T item)
var node = new Node Value = item ;
Node oldTail = null;
bool update = false;
while (!update)
oldTail = _tail;
var oldNext = oldTail.Next;
// Did tail was already updated ?
if (_tail == oldTail)
if (oldNext == null)
// The place is for us
update = Interlocked.CompareExchange(ref _tail.Next, node, null) == null;
else
// another Thread already used the place so give him a hand by putting tail where it should be
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
// At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
Interlocked.CompareExchange(ref _tail, node, oldTail);
Interlocked.Increment(ref _count);
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryDequeue(out T value)
value = default(T);
bool advanced = false;
while (!advanced)
Node oldHead = _head;
Node oldTail = _tail;
Node oldNext = oldHead.Next;
if (oldHead == _head)
// Empty case ?
if (oldHead == oldTail)
// This should be false then
if (oldNext != null)
// If not then the linked list is mal formed, update tail
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
value = default(T);
return false;
else
value = oldNext.Value;
advanced = Interlocked.CompareExchange(ref _head, oldNext, oldHead) == oldHead;
Interlocked.Decrement(ref _count);
return true;
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryPeek(out T value)
if (IsEmpty)
value = default(T);
return false;
Node first = _head.Next;
value = first.Value;
return true;
public void Clear()
_count = 0;
_tail = _head = new Node();
IEnumerator IEnumerable.GetEnumerator()
return InternalGetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator()
return InternalGetEnumerator();
public IEnumerator<T> GetEnumerator()
return InternalGetEnumerator();
IEnumerator<T> InternalGetEnumerator()
Node myHead = _head;
while ((myHead = myHead.Next) != null)
yield return myHead.Value;
void ICollection.CopyTo(Array array, int index)
T[] dest = array as T[];
if (dest == null)
return;
CopyTo(dest, index);
public void CopyTo(T[] dest, int index)
IEnumerator<T> e = InternalGetEnumerator();
int i = index;
while (e.MoveNext())
dest[i++] = e.Current;
public T[] ToArray()
T[] dest = new T[_count];
CopyTo(dest, 0);
return dest;
public void GetObjectData(SerializationInfo info, StreamingContext context)
throw new NotImplementedException();
bool ICollection.IsSynchronized
get return true;
public void OnDeserialization(object sender)
throw new NotImplementedException();
readonly object _syncRoot = new object();
object ICollection.SyncRoot
get return _syncRoot;
public int Count
get
return _count;
public bool IsEmpty
get
return _count == 0;
public class test : MonoBehaviour
class OpcJson
public int Index get; set;
public bool Moto get; set;
public bool Start get; set;
public bool StartWINCC get; set;
public bool Stop get; set;
public bool StopWINCC get; set;
public bool Tag1 get; set;
public bool Tag2 get; set;
//variables
static readonly ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public string receivedFromServer;
WebSocket w = new WebSocket(new Uri("ws://127.0.0.1:8765"));
public Text testert;
public Image moto;
public Image start;
public Image startwincc;
public Image stop;
public Image stopwincc;
public Image tag1;
public Image tag2;
// Use this for initialization
IEnumerator StartWebsocket()
yield return StartCoroutine(w.Connect());
//w.SendString("Hi there");
//int i = 0;
while (true)
string reply = w.RecvString();
if (reply != null)
//Debug.Log(reply);
queue.Enqueue(reply);
//receivedFromServer = reply;
//Debug.Log("Received: " + reply);
//w.SendString("Hi there" + i++);
if (w.error != null)
Debug.LogError("Error: " + w.error);
break;
yield return 0;
w.Close();
private void OnApplicationQuit()
StopAllCoroutines();
w.Close();
IEnumerator JsonObjectSetter(float waitforsecods)
while (true)
queue.TryDequeue(out receivedFromServer);
//string s = receivedFromServer;
//Debug.Log(s);
if(receivedFromServer == null)
Debug.Log("I'm null");
else
var results = JsonConvert.DeserializeObject<OpcJson>(receivedFromServer);
testert.text = results.Index.ToString();
if (results.Moto == true)
moto.GetComponent<Image>().color = Color.green;
else
moto.GetComponent<Image>().color = Color.red;
if (results.Start == true)
start.GetComponent<Image>().color = Color.green;
else
start.GetComponent<Image>().color = Color.red;
if (results.StartWINCC == true)
startwincc.GetComponent<Image>().color = Color.green;
else
startwincc.GetComponent<Image>().color = Color.red;
if (results.Stop == true)
stop.GetComponent<Image>().color = Color.green;
else
stop.GetComponent<Image>().color = Color.red;
if (results.StopWINCC == true)
stopwincc.GetComponent<Image>().color = Color.green;
else
stopwincc.GetComponent<Image>().color = Color.red;
if (results.Tag1 == true)
tag1.GetComponent<Image>().color = Color.green;
else
tag1.GetComponent<Image>().color = Color.red;
if (results.Tag2 == true)
tag2.GetComponent<Image>().color = Color.green;
else
tag2.GetComponent<Image>().color = Color.red;
yield return new WaitForSeconds(waitforsecods);
private void Start()
StartCoroutine(StartWebsocket());
StartCoroutine(JsonObjectSetter(1));
如您所见,我在 JsonObjectSetter 方法中创建了 if/else 语句。每次出队后字符串为空时,它都会打印出“I'm null”,如果它不为空,它会根据值将图像设置为颜色。 我怎样才能做到这样我就不会再得到任何空值了?
编辑 1:在 7 分钟的测试中,我计算了 49 个空值。老实说,这是一个相当大的问题......
【问题讨论】:
【参考方案1】:修好了!
问题是我的python脚本有一个持续1秒的time.sleep()
,将其更改为0.1,并将Unityscript中的WaitForSecods更改为0.25f。这完全解决了我的问题。有点愚蠢,在 *** 上发布之前我没有想到这一点。
【讨论】:
以上是关于python&unity3d:Websocket 稳定性的主要内容,如果未能解决你的问题,请参考以下文章
浅墨Unity3D Shader编程之十三 单色透明Shader & 标准镜面高光Shader
Android + Sqlite + Unity3D 踩过的那些坑 & 全流程简介
UNITY3D 游戏开发之三NGUI && HUDText 的练习源码及资源