简体   繁体   English

Delphi C ++ Indy UDP服务器BytesToString没有收到正确的字符串?

[英]Delphi C++ Indy UDP Server BytesToString does not receive correct string?

I am trying to receive UDP packets from a TUIO multi-simulator. 我正在尝试从TUIO多模拟器接收UDP数据包。 But some of the data is missing. 但是缺少一些数据。

https://www.tuio.org/?specification https://www.tuio.org/?specification

void __fastcall TMain::UDPServerUDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
    TIdSocketHandle *ABinding)
{
    UDPData->Lines->Add(BytesToString(AData));

    for (int i = 0; i < AData.Length; i++)
        UDPData->Lines->Add((char)AData[i]);
}

When I use BytesToString() , I only get the word "#bundle" as a string, but when use the second loop I get this: 当我使用BytesToString() ,我只将单词"#bundle"作为字符串,但是当使用第二个循环时,我得到了:

# bundle #捆绑

/ tuio / 2 D cur , sialive 4 / tuio / 2 D cur , sifffffset ? / tuio / 2 D cur,sialive 4 / tuio / 2 D cur,sifffffset吗?

ホ 9 >  ᅳ ホ 9>

/ tuio / 2 D cur , sifseq # bundle / tuio / 2 D cur,sifseq#束

/ tuio / 2 D obj , salive / tuio / 2 D obj,实际

/ tuio / 2 D obj , sifseq # bundle / tuio / 2 D obj,sifseq#捆绑包

/ tuio / 2 D cur , salive / tuio / 2 D曲线

/ tuio / 2 D cur , sifseq / tuio / 2 D cur,sifseq

With each character on a separate line, of course. 当然,每个字符都放在单独的行上。

So, how can I get the correct data when I don't know the encoding? 因此,当我不知道编码时如何获得正确的数据? I am lost here and need really help. 我在这里迷路了,需要真正的帮助。

Also, how can I send a similar bundle data with TIdUDPClient ? 另外,如何使用TIdUDPClient发送类似的捆绑数据?

The UDP data you showed is mostly binary data with some textual elements inside of it. 您显示的UDP数据主要是二进制数据,其中包含一些文本元素。 As such, you should not be converting the entire AData to a single string with BytesToString() , since it is not entirely text to begin with (well, you could, using BytesToStringRaw() , or BytesToString() with IndyTextEncoding_8bit() as the encoding, but it wouldn't really help you much to do so). 因此,你不应该将整个 AData到一个字符串BytesToString()因为它是不完全的文本开始(嗯,你可以使用BytesToStringRaw()BytesToString()IndyTextEncoding_8bit()作为编码,但这样做并不能真正帮助您)。

You need to break up the data into its individual components, per the protocol specificiation that you linked to (which in turn is based on the Open Sound Control protocol). 您需要根据链接到的协议规范将数据分解成各个组成部分(依次基于Open Sound Control协议)。 Only then can you process the components as needed. 只有这样,您才能根据需要处理组件。 That means you need to loop through the AData byte-for-byte, parsing each byte in context, per the protocol. 这意味着您需要按协议逐个字节地遍历AData ,解析上下文中的每个字节。

For example (this is, by far, not a complete implementation, but it should give you an idea of what kind of logic is involved): 例如(到目前为止,这还不是一个完整的实现,但是应该可以让您了解所涉及的逻辑类型):

struct OSCArgument
{
    char Type;
    Variant Data;
}

struct OSCBundleElement
{
    virtual ~OSCBundleElement() {}
};

struct OSCMessage : OSCBundleElement
{
    String AddressPattern;
    DynamicArray<OSCArgument> Arguments;
};

struct OSCBundle : OSCBundleElement
{
    TDateTime TimeTag;
    DynamicArray<OSCBundleElement*> Elements;

    ~OSCBundle()
    {
        int len = Elements.Length;
        for (int i = 0; i < len; ++i)
            delete Elements[i];
    }
};

int32_t readInt32(const TIdBytes &Bytes, int &offset)
{
    uint32_t ret = GStack->NetworkToHost(BytesToUInt32(Bytes, offset));
    offet += 4;
    return reinterpret_cast<int32_t&>(ret);
}

TDateTime readOSCTimeTag(const TIdBytes &Bytes, int &offset)
{
    int32_t secondsSinceEpoch = readInt32(Bytes, offset); // since January 1 1900 00:00:00
    int32_t fractionalSeconds = readInt32(Bytes, offset); // precision of about 200 picoseconds
    // TODO: convert seconds to TDateTime...
    TDateTime ret = ...;
    return ret;
}

float readFloat32(const TIdBytes &Bytes, int &offset)
{
    uint32_t ret = BytesToUInt32(Bytes, offset);
    offet += 4;
    return reinterpret_cast<float&>(ret);
}

String readOSCString(const TIdBytes &Bytes, int &offset)
{
    int found = ByteIndex(0x00, Bytes, offset);
    if (found == -1) throw ...; // error!
    int len = found - offset;
    String ret = BytesToString(Bytes, offset, len, IndyTextEncoding_ASCII());
    len = ((len + 3) & ~3)); // round up to even multiple of 32 bits
    offset += len;
    return ret;
}

TIdBytes readOSCBlob(const TIdBytes &Bytes, int &offset)
{
    int32_t size = readInt32(Bytes, offset);
    TIdBytes ret;
    ret.Length = size;
    CopyTIdBytes(Bytes, offset, ret, 0, size);
    size = ((size + 3) & ~3)); // round up to even multiple of 32 bits
    offset += size;
    return ret;
}

OSCMessage* readOSCMessage(const TIdBytes &Bytes, int &offset);
OSCBundle* readOSCBundle(const TIdBytes &Bytes, int &offset);

OSCBundleElement* readOSCBundleElement(const TIdBytes &Bytes, int &offset)
{
    TIdBytes data = readOSCBlob(Bytes, offset);
    int dataOffset = 0;

    switch (data[0])
    {
        case '/': return readOSCMessage(data, dataOffset); 
        case '#': return readOSCBundle(data, dataOffset);
    }

    throw ...; // unknown data!
}

Variant readOSCArgumentData(char ArgType, const TIdBytes &Bytes, int &offset)
{
    switch (ArgType)
    {
        case 'i': return readInt32(Bytes, offset);
        case 'f': return readFloat32(Bytes, offset);
        case 's': return readOSCString(Bytes, offset);
        case 'b': return readOSCBlob(Bytes, offset);
        // other types as needed ...
    }

    throw ...; // unknown data!
}

OSCMessage* readOSCMessage(const TIdBytes &Bytes, int &offset)
{
    OSCMessage* ret = new OSCMessage;
    try
    {
        ret->AddressPattern = readOSCString(Bytes, offset);

        String ArgumentTypes = readOSCString(Bytes, offset);
        if (ArgumentTypes[1] != ',') throw ...; // error!

        for (int i = 2; i <= ret->ArgumentTypes.Length(); ++i)
        {
            OSCArgument arg;
            arg.Type = ArgumentTypes[i];
            arg.Data = readOSCArgumentData(arg.Type, Bytes, offset);

            ret.Arguments.Length = ret.Arguments.Length + 1;
            ret.Arguments[ret.Arguments.High] = arg;
        }
    }
    catch (...)
    {
        delete ret;
        throw;
    }

    return ret;
}

OSCBundle* readOSCBundle(const TIdBytes &Bytes, int &offset)
{
    if (readOSCString(Bytes, offset) != "#bundle")
        throw ...; // error!

    OSCBundle *ret = new OSCBundle;
    try
    {
        ret->TimeTag = readOSCTimeTag(Bytes, offset);

        int len = Bytes.Length;
        while (offset < len)
        {
            OSCBundleElement *element = readOSCBundleElement(Bytes, offset);
            try
            {
                ret->Elements.Length = ret->Elements.Length + 1;
                ret->Elements[ret->Elements.High] = element;
            }
            catch (...)
            {
                delete element;
                throw;
            }
        }
    }
    catch (...)
    {
        delete ret;
        throw;
    }

    return ret;
}

void __fastcall TMain::UDPServerUDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
    TIdSocketHandle *ABinding)
{
    int offset = 0;

    if (AData[0] == '/')
    {
        OSCMessage *msg = readOSCMessage(AData, offset);
        // process msg as needed...
        delete msg;
    }
    else if (AData[0] == '#')
    {
        OSCBundle *bundle = readOSCBundle(AData, offset); 
        // process bundle as needed...
        delete bundle;
    }
    else
    {
        // unknown data!
    }
}

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

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