How to read data (xml) sent by server if it doesn't send new line

huangapple go评论87阅读模式
英文:

How to read data (xml) sent by server if it doesn't send new line

问题

假设我们尝试与一个发送XML数据的服务器(XMPP)进行通信。我们可以使用以下代码:

conn, err := net.Dial("tcp", s.Addr+":5222")
//...
r := bufio.NewReader(conn)
//...
s, err := s.R.ReadString(10) // 读取字符串

但是有一个问题,服务器没有发送\10(换行)符号。我也尝试了\12,但没有成功。对于readLine函数也是一样,它也依赖于\10。那么我该如何读取服务器发送的数据呢?
我尝试使用'>'作为分隔符,并成功接收到了消息的部分内容(可预测的)。我有一个想法,就是在错误为nil的情况下循环,并使用'>'作为分隔符,但这也没有起作用。
我的研究表明,消息的最后一个符号确实是'>'(62),在末尾没有其他任何内容。

英文:

Let's say we try to communicate with a server (XMPP) which sends back XML data. We can use

conn, err := net.Dial("tcp", s.Addr+":5222")
//...
r := bufio.NewReader(conn)
//...
s, err := s.R.ReadString(10) // to read a string

But there is one problem that the server doesn't send the \10 (newline) symbol. I also tried 12 but without any luck. Same goes for readLine function as it also relies on \10. So how do I read the data sent by server?
I tried using '>' as a delimiter and succeeded to receive only parts of the messages (predictable). I had an idea to loop while error is nil and use delimiter of '>' but it also didn't work.
My research shown that the last symbol of the message is really '>' (62) and there is not any anything else at the end.

答案1

得分: 1

使用xml.Decoder来从XMPP流中读取数据块。

conn, err := net.Dial("tcp", s.Addr+":5222")
if err != nil {
    // 处理错误
}
dec := xml.NewDecoder(conn)

使用解码器的Token方法来读取根文档元素,并跳过数据块之间的字符数据:

func readStartElement(dec *xml.Decoder) (xml.StartElement, error) {
    for {
        t, err := dec.Token()
        if err != nil {
            return xml.StartElement{}, err
        }
        switch t := t.(type) {
        case xml.StartElement:
            return t, nil
        }
    }
}

使用解码器的DecodeElement方法来读取一个数据块:

func readStanza(dec *xml.Decoder) (interface{}, error) {
    se, err := readStartElement(dec)
    if err != nil {
        return nil, err
    }
    var v interface{}
    switch se.Name.Space + " " + se.Name.Local {
    case "jabber:client message":
        v = &jabberMessage{} // jabberMessage是应用程序定义的消息结构类型
    // 在这里添加其他数据块类型
    default:
        v = &struct{}{}
    }
    if err := dec.DecodeElement(v, &se); err != nil {
        return nil, err
    }
    return v, nil
}

使用type switch来处理接收到的不同类型的数据块。

客户端同步读取数据块。以下是一个大致的概述(忽略身份验证等):

conn, err := net.Dial("tcp", s.Addr+":5222")
if err != nil {
    // 处理错误
}
dec := xml.NewDecoder(conn)

// 读取并丢弃根元素
_, err := readStartElement(dec)
if err != nil {
    // 处理错误
}

// 读取数据块
for {
    v, err := readStanza(dec)
    if err != nil {
        // 处理错误
        // 必须在错误时跳出循环
    }
    switch v := v.(type) {
    case *jabberMessage:
        // 处理消息
    case *someOtherStanzaType:
        // 处理其他数据块类型
        // ...以此类推
    }
}
英文:

Use an xml.Decoder to read stanzas from an XMPP stream.

conn, err := net.Dial("tcp", s.Addr+":5222")
if err != nil {
    // handle error
}
dec := xml.NewDecoder(conn)

Use the decoder Token method to read the root document element and to skip over character data between stanzas:

func readStartElement(dec *xml.Decoder) (xml.StartElement, error) {
    for {
        t, err := dec.Token()
        if err != nil {
            return xml.StartElement{}, err
        }
        switch t := t.(type) {
        case xml.StartElement:
            return t, nil
        }
    }
}

Use the decoder DecodeElement method to read a stanza:

func readStanza(dec *xml.Decoder) (interface{}, error) {
    se, err := readStartElement(dec)
    if err != nil {
        return nil, err
    }
    var v interface{}
    switch  se.Name.Space + " " + se.Name.Local {
    case "jabber:client message":
        v = &jabberMessage{} // jabberMessage is struct type defined by app for messages
    // Add other stanza types here.        
    default:
        v = &struct{}{}
    }
    if err := dec.DecodeElement(v, &se); err != nil {
        return nil, err
    }
    return v, nil
}

Type switch on the return value from readStanza to handle the different types of received stanzas.

A client reads stanzas synchronously. Here's rough outline (ignoring authentication, etc).

conn, err := net.Dial("tcp", s.Addr+":5222")
if err != nil {
    // handle error
}
dec := xml.NewDecoder(conn)

// read and discard root element
_, err := readStartElement(dec)
if err != nil {
     // handle error
}

// read stanzas
for {
   v, err := readStanza(dec)
   if err != nil {
       // handle error 
       // must break out of loop on error
   }
   switch v := v.(type) {
   case *jabberMessage:
        // handle message
   case *someOtherStanzaType:
        // handle other stanza types
        // ... and so on
   }
}

huangapple
  • 本文由 发表于 2016年3月20日 02:00:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/36105199.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定