ACE 7.0.6无法正确检测/处理带FIN捎带的应用数据问题求助
问题分析与解决方案
核心问题原因
SSL Socket返回值逻辑完全颠倒
普通TCP Socket中,recv返回0表示收到FIN包(连接正常关闭),返回-1表示出错;但你的代码把req_size_read == 0当成错误,==-1当成EOF,完全搞反了逻辑,导致FIN捎带数据时无法正确识别关闭信号。
更关键的是,ACE_SSL_SOCK_Stream的recv行为和普通Socket有差异:当SSL连接收到FIN时,recv会返回-1,需通过SSL_get_error判断是否为SSL_ERROR_ZERO_RETURN(表示对方正常关闭),而非返回0。MSG_PEEK的误用
你在handleIncomingData中用MSG_PEEK仅探测1字节数据,仅当返回值为1时才进入读取流程。若FIN捎带的数据长度大于1,或SSL层内部缓冲导致peek结果不符合预期,会直接触发错误分支,跳过正常数据读取。循环读取未适配SSL特性
SSL连接中,即使底层TCP收到FIN,SSL层可能还有未读取的应用数据,你的循环逻辑未处理“读完所有数据再处理关闭”的场景。
修复方案
1. 纠正recv返回值判断逻辑
针对ACE_SSL_SOCK_Stream的特性,正确处理返回值与SSL错误。
2. 移除不合理的MSG_PEEK探测
直接进入数据读取流程,避免误判。
3. 完善循环读取逻辑
读完所有可用数据后,再处理连接关闭信号。
修改后的代码示例
int SSLStreamConnection::handle_input(ACE_HANDLE hd) { switch (getState()) { case CONNECTED: handleIncomingData(); break; //... } return 0; // 返回ACE标准处理值,避免事件循环异常 } void SSLStreamConnection::handleIncomingData() { readIncomingData(); } void SSLStreamConnection::readIncomingData() { std::array<char, 128> strDebug = { 0 }; char* req_data_buf = nullptr; int req_buf_size = 0; ssize_t req_size_read = 0; bool connection_closed = false; while (true) { appCallback->rxBufferRequest(DEF_TRANSPORT_BUFFER_SIZE, req_data_buf, req_buf_size); const size_t tbuf_size = req_buf_size; req_size_read = socket.recv(req_data_buf, tbuf_size - 1, 0); if (req_size_read > 0) { // 正常读取到数据,传递给应用层 if (appCallback) appCallback->receiveData(id, SOCK_RX_DATA, static_cast<int>(req_size_read), req_data_buf, peerAddr, context); } else if (req_size_read == 0) { // 普通TCP场景的FIN,SSL场景下极少出现,标记为异常关闭 sprintf_s(strDebug.data(), strDebug.size(), "异常关闭 socketId=%u, errno=0x%x", id, errno); logError(strDebug.data()); connection_closed = true; appCallback->rxBufferFreeCallback(req_data_buf, req_buf_size); break; } else // req_size_read == -1 { // 处理SSL层错误 unsigned long ssl_err = SSL_get_error(socket.ssl(), static_cast<int>(req_size_read)); if (ssl_err == SSL_ERROR_ZERO_RETURN) { // SSL层收到FIN,连接正常关闭 sprintf_s(strDebug.data(), strDebug.size(), "连接正常关闭 socketId=%u", id); logWarning(strDebug.data()); connection_closed = true; } else if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { // SSL需要重试读写,释放缓冲区后退出循环,等待下一次事件触发 appCallback->rxBufferFreeCallback(req_data_buf, req_buf_size); break; } else { // 其他SSL错误,异常关闭 sprintf_s(strDebug.data(), strDebug.size(), "SSL错误 socketId=%u, err=0x%x", id, ssl_err); logError(strDebug.data()); connection_closed = true; } appCallback->rxBufferFreeCallback(req_data_buf, req_buf_size); break; } } if (connection_closed && appCallback) { appCallback->receiveData(id, SOCK_CONNECTION_CLOSED, 0, nullptr, peerAddr, context); // 移除读事件掩码,避免重复触发handle_input reactor()->remove_handler(this, ACE_Event_Handler::READ_MASK); } }
额外注意事项
- 调用
reactor()->remove_handler移除读掩码,防止连接关闭后仍收到无效读事件。 - 处理
SSL_ERROR_WANT_READ/WANT_WRITE:这是SSL层的正常重试请求,需退出当前循环,等待ACE Reactor再次触发事件后继续处理。 - 不要依赖
MSG_PEEK探测SSL连接状态,SSL层内部缓冲会导致peek结果不准确。
内容的提问来源于stack exchange,提问作者Samer Nabulsi
相关产品推荐
相关产品推荐

