假设我们为服务器提供了以下抽象(XMPP,但这里并不重要):
type Server struct {
Addr string
Conn net.Conn
tlsCon *tls.Conn
R *bufio.Reader
SSL bool
reader chan string
}
启动它的辅助函数:
func createServer(domain string) (s *Server, err error) {
conn, err := net.Dial("tcp", domain+":5222")
if err != nil {
return nil, err
}
s = &Server{domain, conn, nil, bufio.NewReader(conn), false, make(chan string, 8)}
go func(t *Server) {
for {
buf := bufsPool.Get().([]byte)
n, err := s.R.Read(buf)
if err == nil {
s.reader <- string(buf[:n])
} else {
fmt.Println(err)
}
}
}(s)
return s, err
}
这个想法很简单:创建连接,如果一切顺利,请为它获取缓冲读取器(我不使用conn.read函数,因为,如果服务器需要,我启动TLS连接并重新分配R到基于它创建的阅读器,但现在情况并非如此)。
现在我们有两个函数,写和读:
func (s *Server) read() (t string) {
t = ""
Inn:
for {
select {
case u := <-s.reader:
fmt.Println("debug", u)
t += u
default:
break Inn
}
}
return t
}
所以我希望read函数接收goroutine发送的数据,该数据从chan中读取socket(在createServer()中启动的那个)。想法是调用write而不是读取响应。我创建了所有这些因为服务器有时会将响应作为两个部分发送,例如我必须做传统的read()2次。 但这不起作用,我的阅读功能(见上文)根本不返回任何内容。最有可能的是,这是因为服务器无法回送数据并且我的功能退出,因为chan中没有任何内容。但有一个问题是虽然我多次调用write和read,但read总是不返回任何内容。
所以我想我有一些一般的设计错误,问题是社区是否可以帮助我找到它。感谢。
答案 0 :(得分:1)
问题是你的select
选择了默认分支,因为读取器通道中没有任何内容,所以它会立即中断。 (https://golang.org/ref/spec#Select_statements)
您希望读取阻止,直到您收到足够的数据。例如。如果您知道您的回复需要以“\ n”结尾,请继续阅读并且在收到“\ n”之前不要中断,或者关闭频道。
如果传入的数据是换行符分隔的,并且使用chan string
将整个字符串传递给另一个goroutine,或许更好的解决方案是在阅读器中使用goroutine中的bufio.Scanner,并使用is_global = remote_conn.recv(1024)
将整个字符串传递给另一个goroutine。
您也可以使用Scanner.Split设置不同的分割功能。
(另见关于tcp和分隔符的问题和答案:Golang: TCP client/server data delimiter)
编辑:使用xml.Decoder.Token,您可以继续从流中读取令牌,并适当地处理它们。您可以将其与Decode(这将解码下一个令牌)或DecodeElement(这允许您解码刚刚读取的令牌)组合以解码xml。