简体   繁体   English

在Python中读取LabVIEW TCP数据(平化字符串/数据簇)

[英]Reading LabVIEW TCP data (Flattened String / Data Cluster) in Python

I have a LabVIEW application that is flattening a cluster (array) of Doubles to a string, before transmitting over TCP/IP to my python application. 我有一个LabVIEW应用程序,该应用程序在将TCP / IP传输到我的python应用程序之前,将Doubles的群集(数组)展平为字符串。 It does this because TCP/IP will only transmit strings. 这样做是因为TCP / IP将仅传输字符串。

The problem is that python reads the string as a load of nonsense ASCII characters, and I can't seem to unscramble them back to the original array of doubles. 问题在于python将字符串作为无意义的ASCII字符读取,并且我似乎无法将它们解译回原始的double数组。

How do I interpret the string data that LabVIEW sends after flattening a data strings. 扁平化数据字符串后,如何解释LabVIEW发送的字符串数据。 My only hint of useful information after hours of google was a PyPI entry called pyLFDS, however it has since been taken down. 在Google工作数小时后,我唯一有用的信息提示是一个名为pyLFDS的PyPI条目,但是此后就被删除了。

The LabVIEW flattened data format is described in some detail here . 此处将详细介绍LabVIEW展平的数据格式。 That document doesn't explicitly describe how double-precision floats (DBL type) are represented, but a little more searching found this which clarifies that they are stored in IEEE 754 format . 该文档没有明确描述双精度浮点数(DBL类型)的表示方式,但是更多的搜索发现了这一点 ,从而澄清了它们以IEEE 754格式存储。

However it would probably be simpler and more future proof to send your data in a standard text format such as XML or JSON, both of which are supported by built-in functions in LabVIEW and standard library modules in Python. 但是,以标准文本格式(例如XML或JSON)发送数据可能会更简单,并且将来更可靠,而LabVIEW中的内置函数和Python中的标准库模块都支持这两种格式。

A further reason not to use LabVIEW flattened data for exchange with other programs, if you have the choice, is that the flattened string doesn't include the type descriptor you need to convert it back into the original data type - you need to know what type the data was in order to decode it. 如果可以选择,不使用LabVIEW展平数据与其他程序交换的另一个原因是,展平字符串不包含类型描述符,您需要将其转换回原始数据类型-您需要知道什么键入数据是为了对其进行解码。

I wanted to document the problem and solution so others can hopefully avoid the hours I have wasted looking for a solution on google. 我想记录问题和解决方案,以便其他人希望避免浪费我在Google上寻找解决方案的时间。

When LabVIEW flattens data, in this case a cluster of doubles, it sends them simply as a concatonated string with each double represented by 8 bytes. 当LabVIEW对数据进行展平时(在这种情况下为双精度簇),它会简单地将它们作为连接字符串发送,每个双精度整数均由8字节表示。 This is interpreted by python as 8 ASCII characters per double, which appears as nonsense in your console . python将其解释为每双精度8个ASCII字符, 在控制台中显示为废话

To get back to the transmitted doubles, you need to take each 8-byte section in turn and convert the ASCII characters to their ASCII codes, in Python's case using ord(). 要返回发送的双精度数,您需要依次获取每个8字节的部分,并将ASCII字符转换为它们的ASCII代码,在Python的情况下,使用ord()。 This will give you an 8 bytes of decimal codes (eg 4.8 = [64 19 51 51 51 51 51 51] ) 这将为您提供8字节的十进制代码(例如4.8 = [64 19 51 51 51 51 51 51]

It turns out that LabVIEW does most things, including TCP/IP transmissions, Big Endian. 事实证明,LabVIEW可以完成大多数工作,包括TCP / IP传输,Big Endian。 Unless you are working Big Endian, you will probably need to change it around. 除非您正在使用Big Endian,否则可能需要进行更改。 For example the example above will become [51 51 51 51 51 51 19 64] . 例如,上面的示例将变为[51 51 51 51 51 51 19 64] I put each of my doubles into a list, so was able to use the list(reversed()) functions to change the endienness. 我将每个双打放入列表中,因此能够使用list(reversed())函数更改字节序。

You can then convert this back to a double. 然后,您可以将其转换回为double。 Example python code: 示例python代码:

import struct
b = bytearray([51,51,51,51,51,51,19,64]) #this is the number 4.8
value = struct.unpack('d', b)

print(value) #4.8

This is probably obvious to more experienced programmers, however it had me flummuxed for days. 对于经验丰富的程序员来说,这可能是显而易见的,但是让我迷糊了好几天。 I apologise for using stackoverflow as the platform to share this by answering my own question, but hopefully this post helps the next person who is struggling. 我很抱歉使用stackoverflow作为平台来回答我自己的问题,以分享这一点,但希望这篇文章对下一个苦苦挣扎的人有所帮助。

EDIT: Note if you are using an earlier version than Python 2.7.5 then you might find struct.unpack() will fail. 编辑:请注意,如果您使用的是比Python 2.7.5更早的版本,则您可能会发现struct.unpack()将失败。 Using the example code above substituting the following code worked for me: b = bytes(bytearray([51,51,51,51,51,51,19,64])) 使用上面的示例代码替换下面的代码对我b = bytes(bytearray([51,51,51,51,51,51,19,64]))b = bytes(bytearray([51,51,51,51,51,51,19,64]))

This code works for me. 该代码对我有用。 UDP server accept flattened dbl array x, return x+1 to port 6503. Modify LabView UDP client to your needs. UDP服务器接受扁平化的dbl数组x,将x + 1返回到端口6503。根据需要修改LabView UDP客户端。

import struct
import socket
import numpy as np

def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

#bind_ip = get_ip()

print("\n\n[*] Current ip is %s" % (get_ip()))
bind_ip = ''
bind_port = 6502

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind((bind_ip,bind_port))  

print("[*] Ready to receive UDP on %s:%d" % (bind_ip,bind_port))

while True:
    data, address = server.recvfrom(1024)
    print('[*] Received %s bytes from %s:' % (len(data), address))

    arrLen = struct.unpack('>i', data[:4])[0]
    print('[*] Received array of %d doubles:' % (arrLen,))
    x = []
    elt = struct.iter_unpack('>d', data[4:])
    while True:
        try:
            x.append(next(elt)[0])
            print(x[-1])
        except StopIteration:
            break
    x = np.array(x)
    y = x+1 # np.sin(x)
    msg = data[:4]
    for item in y:
        msg += struct.pack('>d', item)
    print(msg)
    A = (address[0], 6503)
    server.sendto(msg, A)
    break

server.close()
print('[*] Server closed')
print('[*] Done')

LabView UDP client: LabView UDP客户端: LabView UDP客户端

I understand that this does not solve your problem as you mentioned you didn't have the ability to modify the LabVIEW code. 我知道这不能解决您的问题,因为您提到您没有修改LabVIEW代码的能力。 But, I was hoping to add some clarity on common ways string data is transmitted over TCP in LabVIEW. 但是,我希望在LabVIEW中通过TCP传输字符串数据的常用方式上增加一些清晰度。

The Endianness of the data string sent through the Write TCP can be controlled. 可以控制通过Write TCP发送的数据字符串的字节序。 I recommend using the Flatten To String Function as it gives you the ability to select which byte order you want to use when you flatten your data; 我建议使用Flatten To String Function,因为它可以让您选择在展平数据时要使用的字节顺序; big-endian (default if unwired), native (use the byte-order of the host machine), or little-endian. big-endian(如果未连接则为默认值),native(使用主机的字节顺序)或little-endian。

Another common technique I've seen is using the Type Cast Function . 我见过的另一种常见技术是使用Type Cast函数 Doing this will convert the numeric to a big-endian string. 这样做会将数字转换为大端字符串。 This of course can be confusing when you read it on the other end of the network as most everything else is little-endian, so you'll need to do some byte-swapping. 当您在网络的另一端阅读它时,这当然会造成混淆,因为大多数其他内容都是低位优先的,因此您需要进行一些字节交换。

In general, if you're not sure what the code looks like, assume that it will be big-endian if its coming from LabVIEW code. 通常,如果您不确定代码是什么样子,请假设它来自LabVIEW代码,则将是big-endian。

The answer from nekomatic is good one. 来自nekomatic的答案是一个很好的答案。 Using a standard text format when available is always a good option. 在可用时使用标准文本格式始终是一个不错的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM