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 的练习源码及资源

Android + Sqlite + Unity3D 踩过的那些坑 & 全流程简介

Unity3D 判断鼠标是否按在UGUI上

2019.9.18 Unity3D与Android相互传递消息 & unity与ios相互传递消息