• golang调用百度音转文websocket服务“invalid frame type”错误排查及解决


    背景

    本文旨在记录解决问题的办法及思路。

    需求是识别视频中的话语转为文字,此服务是调用的百度的websocket服务,其要求是:

    • 发送一个text类型的帧,用于登录。
    • 后续发送binary类型的音频数据。

    开发语言:Golang
    websocket库:github.com/gorilla/websocket

    demo

    核心流程就四步:连接服务器,发送text类型的登录消息,写音频数据,接收识别内容

    package baidu
    
    import (
    	"fmt"
    	"github.com/gorilla/websocket"
    	"io/ioutil"
    	"os"
    	"time"
    )
    
    func demo() error {
    	dialer := &websocket.Dialer{
    		HandshakeTimeout: 3 * time.Second,
    	}
    	url := genUrl("testsn")
    	conn, _, err := dialer.Dial(url, nil)
    	if err != nil {
    		return err
    	}
    
    	//登录验证的消息
    	if err := conn.WriteJSON(newStartMsg("dummy")); err != nil {
    		return err
    	}
    	f, err := os.Open("/data/16k-0.pcm")
    	if err != nil {
    		return err
    	}
    	data, err := ioutil.ReadAll(f)
    	if err != nil {
    		return err
    	}
    
    	//从websocket中读
    	go func() {
    		for {
    			_, b, err := conn.ReadMessage()
    			if err != nil {
    				return
    			} else {
    				fmt.Printf("%s
    ", b)
    			}
    		}
    	}()
    
    	total := int64(len(data))
    	var (
    		start int64
    		len   int64 = 5120
    		end   int64
    	)
    
    	//写入音频二进制文件
    	for start < (total) {
    		end = start + len
    		if end > total {
    			end = total
    		}
    		if err := conn.WriteMessage(websocket.BinaryMessage, data[start:end]); err != nil {
    			return err
    		}
    		start = end
    		time.Sleep(time.Millisecond * 160)
    	}
    
    	time.Sleep(time.Second * 3)
    	return nil
    }
    
    

    错误排查

    确定方向

    通过go test调用demo后,给出以下结果:

    === RUN   TestDemo
    {"err_msg":"invalid frame type","err_no":-3201,"log_id":1953719668,"type":"FIN_TEXT"}
    

    其提示为“invalid frame type”,那么有可能是以下的情况:

    • 我指定的frame type不对,但是通过检查,再三确认是Binary类型,此项排除。
    • websocket库的实现有问题,但是在github上有13k的star,暂时排除
    • 百度的服务有问题,百度官方虽然没有golang的sdk,但是有Python的,运行过Python的sdk后,是能得到预期的

    既然如此,那就是自己的问题了?

    抓包

    既然提示“invalid frame type”那么就抓一下看看是不是真的有问题。打开wireshark,过滤条件为“websocket”。运行程序:

    如图所示,第一个是登录的text帧,第二个是音频的binary,第三个为什么不是binary,而是个continuation?

    这里简单说明一下帧类型:

    • opcode=0x1 :表示发送的是文本类型
    • opcode=0x2 :表示发送的是二进制类型
    • opcode=0x0 :表示发送的延续帧,就是完整消息对应的数据帧还没接收完。

    而FIN=1,表示数据已接收完;而FIN=0,表示数据未接收完。

    看来问题就是出在continuation帧上,看一下binary、continuation帧的头

    binary帧

    continuation帧

    从上面两图可看出binary帧长度4096+continuation帧长度1024,正好等于程序里写的5120。但是为什么会分帧呢?

    debug

    通过从conn.WriteMessagedebug

    最终发现原因:gorilla/websocket客户端writebuffer默认大小为defaultWriteBufferSize(4096)个字节。这就对上了。

    解决方法

    解决方法非常简单,就是设置writebuffer的大小

    dialer := &websocket.Dialer{
          HandshakeTimeout: 3 * time.Second,
          WriteBufferSize:  20000,
    }
    

    再次进行测试时就ok了

  • 相关阅读:
    SQL Server 判断各种对象是否存在和sysobjects的关系
    SQL Server 通过“with as”方法查询树型结构
    js Iframe与父级页面通信及IE9-兼容性
    SQL Server Update 链接修改和when的应用
    C# 使用表达式树获取特性的值
    .Net Core 防止跨站点请求伪造
    SQL Server 待定
    C# Http请求
    C# Linq 笛卡尔积
    SQL Server 存储过程、函数、触发器的定义
  • 原文地址:https://www.cnblogs.com/flhs/p/14203298.html
Copyright © 2020-2023  润新知