我在从套接字读取数据时遇到问题。有一个星号实例正在运行大量调用(一分钟 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。
更新至Asterisk最新版本(13.x); 1.8 已经落后了三个主要版本。以前的版本有一个错误,比如 AMI 发送大量数据时。
要检查问题,您已通过 AMI 命令(如
COMMAND sip show peers
)(或任何其他长输出命令)发送并查看结果。
问题出在操作系统套接字缓冲区溢出。 AMI 实例中似乎有太多数据需要处理。
有三种可能的方法可以解决此问题:
默认情况下,Gami 读取 Asterisk 中的所有数据。我正在阅读所有这些内容,并在实际读取操作后过滤它们。由于 AMI 监听应用程序运行在资源非常有限的机器上,因此在超出缓冲区容量之前,它似乎无法读取所有数据。
但是,通过将“Events”操作发送到 AMI 并指定所需的“EventMask”,可以仅接收特定事件。
我的解决方案是为不同的事件类型创建不同的连接。
我在读取数据时也遇到了问题。我必须为它创建一个单独的线程(一个 Go 例程)并通过通道发送结果,但后来我意识到 读取本身会阻塞客户端路由,因为它等待结束(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)