我在从套接字读取数据时遇到问题。有一个星号实例正在运行大量调用(一分钟 10-60 个),我正在尝试读取和处理与这些调用相关的 CDR 事件(连接到 Amazon 机器实例)。
这是我正在使用的库(不是我的,而是由于错误而分叉的)https://github.com/warik/gami
这非常简单;主要操作在 gami.go - readDispatcher 中。
buf := make([]byte, _READ_BUF) // read buffer
for {
rc, err := (*a.conn).Read(buf)
因此,有一个 TCP 连接 (a.conn) 和一个大小为 1024 的缓冲区,我正在从套接字读取消息。到目前为止一切顺利,但最终(该时间可能从 10 分钟到 5 小时不等,与通过套接字传输的数据量无关),读取操作会失败并出现 io.EOF 错误。
我尝试立即重新连接并重新登录,但这不起作用;连接超时,所以我被迫等待大约 40-60 秒才能重新连接。这个时间延迟对我来说非常关键;由于延迟,我丢失了大量数据。在 Python 或 PHP 中打开这样一个简单的套接字不会以同样的方式失败。
可能是什么问题?
问题可能是由于:
但我不确定。有什么想法吗?
我正在使用 Go 1.2.1 linux/amd64 和 Asterisk 1.8。
更新到最新的星号。当AMI发送大量数据时出现这样的错误。
对于检查问题,您可以通过 ami 命令发送,例如“COMMAND sip show peers”(或任何其他长输出命令)并查看结果。
好的,问题出在操作系统套接字缓冲区溢出。看来有太多数据需要处理。
因此,有三种可能的方法可以解决此问题:
gami 默认情况下读取 asterisk 中的所有数据。我正在阅读所有这些内容,并在实际读取操作后过滤它们。根据 AMI 侦听应用程序在相当差的 PC 上运行的情况,它似乎无法在暴露缓冲区容量之前读取所有数据。但是,通过向 AMI 发送“事件”操作并指定所需的“EventMask”,可以仅接收特定事件”。 所以,我的决定就是这么做。并为不同的事件类型创建不同的连接。
我在读取数据时也遇到了问题。我必须为它创建一个单独的线程(goroutine)并通过chanel发送结果。然后它像一道闪电一样击中了我。 读取本身会阻塞客户端 rutin ,因为它等待结束(EOF),但是给定的线程还必须执行除等待读取之外的其他操作,因此读取必须在单独的线程(例程)中启动,这是一个例子。它通过通道发送读取结果。
go func(mch chan string, conn net.Conn, ctx context.Context) {
reader := bufio.NewReader(conn)
for {
s, err := reader.ReadString('#')
if err != nil {
mch <- "[read stop] " + fmt.Sprint(err)
break
} else {
mch <- s
}
select {
case <-ctx.Done():
return
default:
za.SleepM(3)
}
}
}(mch, conn, ctx)