英文:
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
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论