使用SSL_peek查找HTTP头分隔符时为何返回重复数据?
SSL_peek处理大HTTP头部时无法找到分隔符的原因及解决
问题场景
使用以下C++代码通过SSL_peek查找HTTP头部分隔符\r\n\r\n,处理小型响应正常,但大头部响应时无法找到分隔符,调试发现peek_buf存在重复数据:
int TcpClient::PeekEndOfDelimiter(const std::vector<unsigned char>& delimiter, int max_size) { std::vector<unsigned char> peek_buf(max_size); int total_bytes_peeked = 0; while (total_bytes_peeked < max_size) { int bytes_peeked = -1; bytes_peeked = SSL_peek(ssl, peek_buf.data() + total_bytes_peeked, max_size - total_bytes_peeked); if (bytes_peeked <= 0) return -1; total_bytes_peeked += bytes_peeked; auto found = std::search(peek_buf.begin(), peek_buf.begin() + total_bytes_peeked,delimiter.begin(), delimiter.end()); if (found != peek_buf.begin() + total_bytes_peeked) return found - peek_buf.begin() + delimiter.size(); } return -1; }
问题核心:阻塞上下文且响应已就绪时,为何多次SSL_peek会产生重复数据,导致无法找到分隔符?
原因分析
你误解了SSL_peek的工作逻辑:
SSL_peek的作用是查看SSL接收缓冲区中已有的数据,但不会从缓冲区中移除这些数据。- 在阻塞模式下,第一次调用
SSL_peek会返回当前缓冲区所有可用数据;如果没有新数据到达,后续调用SSL_peek会重复返回这批已存在的数据。 - 你的循环逻辑是每次调用
SSL_peek都往peek_buf的后续位置写入,但第二次调用时写入的还是第一次的重复数据,导致缓冲区被覆盖,分隔符如果跨第一次和真实的第二次数据段,会被重复数据覆盖,永远无法被std::search找到。
解决方法
方案1:单次SSL_peek读取后查找(推荐,适配HTTP头部场景)
直接单次调用SSL_peek读取最大允许的字节数,再在完整的缓冲区中查找分隔符。阻塞上下文下,若响应已就绪,单次调用就能获取所有可用的头部数据:
int TcpClient::PeekEndOfDelimiter(const std::vector<unsigned char>& delimiter, int max_size) { std::vector<unsigned char> peek_buf(max_size); int bytes_peeked = SSL_peek(ssl, peek_buf.data(), max_size); if (bytes_peeked <= 0) return -1; auto found = std::search(peek_buf.begin(), peek_buf.begin() + bytes_peeked, delimiter.begin(), delimiter.end()); if (found != peek_buf.begin() + bytes_peeked) return found - peek_buf.begin() + delimiter.size(); return -1; }
方案2:分批次读取时跟踪已处理数据(复杂场景用)
若必须分批次读取,每次peek后需要通过SSL_read将已查看的数据从SSL缓冲区中移除,或者维护一个偏移量,确保后续peek的是新数据。但此方式复杂度高,HTTP头部场景不推荐。
额外注意事项
确保max_size设置合理,建议至少设置为8KB以上,覆盖绝大多数HTTP头部的大小;若头部超过max_size,函数会返回-1,需根据业务场景调整该值。
内容的提问来源于stack exchange,提问作者Jozese
相关产品推荐
相关产品推荐

