采用正则解析协议

大家都知道开发网络协议的C++一般是很少的,比如HTTP、RTSP、SIP等就很少,如果有特殊需求基本上已经没有什么可以使用的库了,所以C++程序员一般热衷于造轮子。记得之前做异步HTTP的时候,基本都是ASIO做网络I/O,数据自己来做解析,各种的匹配,逐条处理等等。

比如在解析HTTP文本的时候,基本就是先找CRLF,取出单条,然后再找分割符,然后再取值前后TRIM等,写起来相当的不方便,参考网上其他人的解析基本还是一个字节一个字节的往后偏移查找,效率就更慢了,也很难支持异步数据处理。

最近想调测下RTSP协议的推流等,主要还是要解析RTSP协议,live555不好用,而且网络模型不太合适,打算自己写个新的通信框架。在GITHUB上搜索了下,也没什么合适的解析库,还好RTSP协议也是文本方式的请求响应模式,大概如下

OPTIONS rtsp://xxx.xxx.xxx.xxx:554/tcp.sdp RTSP/1.0
CSeq: 1
User-Agent: Lavf56.23.105

RTSP/1.0 200 OK
Server: DSS/7.0.0 (Build/15.0310; Release/EasyDarwin; State/Development; )
Cseq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD

其实都是有固定格式的,不由得的想到了正则表达式,觉得很多匹配应该交由正则来实现,比如解析请求的时候,基本上就是首行+头域+负载三部分构成。首行和头域都是以换行(CRLF)分割的,我们只需要解析出一行行的字符串,然后去正则匹配就可以取出想要的Token了。比如首行取出请求命令和URI的代码如下

std::string line = "PLAY rtsp://xx.a.a/xxxx/aa?dd=22 RTSP/1.0";
const std::regex pattern("(\\w{4,})\\s(\\S{1,})\\sRTSP\\/1.0");
std::match_results<std::string::const_iterator> result;
bool valid = std::regex_match(line, result, pattern);
if(valid)
{
puts(result[1].str().c_str());
puts(result[2].str().c_str());
}

就会取出 PLAYrtsp://xx.a.a/xxxx/aa?dd=22, 非常方便。再如头域的K/V提取

std::string line = "Test-Key: DDD ddd \"dd\", xx=aaa ()001///dd";
const std::regex pattern("(\\w{1,}):\\s*([^\f\n\r\t\v]+)");
std::match_results<std::string::const_iterator> result;
bool valid = std::regex_match(line, result, pattern);
if(valid)
{
puts(result[1].str().c_str());
puts(result[2].str().c_str());
}

可以取出 Test-KeyDDD ddd "dd", xx=aaa ()001///dd, 这样整个消息解析起来就会非常方便。

最近的文章

C++字符串格式化库

总的来说,C++可使用的字符串格式化库是非常少,基本可选用的如sprintf系列,boost.format等,诚然stringstream也可以,但是和其他库有明显使用上的区别,不是很方便。 自实现的格式化库曾经因为项目日志打印问题,比如申请多少缓冲区问题,为了防止越界等问题,多方考虑自己实现了一个 …

技术 继续阅读
更早的文章

通过28181与WebRTC直播摄像头

前文描述了WebRTC视频直播技术,后续应用到系统中,版本已经做出来了并封装了JS的SDK,实时性效果还是非常令人惊喜的,针对部分调整和问题进行记录。 视频源项目使用的是海康摄像头,我打算取消本地服务器,直接让摄像头通过GB28181协议进行推流。为了让所有用户可以观看,将服务部署在公网,当然这里需 …

技术 继续阅读