32位ISAPI扩展:HSE_REQ_TRANSMIT_FILE大文件偏移替代方案咨询
解决ISAPI扩展中HSE_REQ_TRANSMIT_FILE处理4GB以上文件偏移的问题
刚好之前处理过类似的大文件ISAPI场景,给你两个可行的解决方案:
1. 使用官方扩展结构 HSE_TF_INFO_EX
IIS 6.0及以后版本提供了HSE_TF_INFO的64位扩展版本HSE_TF_INFO_EX,专门解决大文件偏移的问题。这个结构和原结构的核心区别是把单一的DWORD Offset拆分成了Offset和OffsetHigh两个DWORD成员,组合起来支持完整的64位偏移量。
使用时需要注意两个关键点:
- 必须设置
dwSize为sizeof(HSE_TF_INFO_EX),让IIS识别这是扩展结构 - 在
dwFlags中添加HSE_TF_FLAG_USE_EX_INFO标记
示例代码如下:
// 假设fileOffset是存储图片起始位置的64位偏移量(DWORD64类型) DWORD64 fileOffset = ...; DWORD imageSize = ...; // 图片大小,小于100KB HANDLE hBigFile = ...; // 已打开的大文件句柄(需支持大文件访问) HSE_TF_INFO_EX tfInfoEx = {0}; tfInfoEx.dwSize = sizeof(HSE_TF_INFO_EX); // 标记使用扩展结构,同时按需添加其他标记(比如发送原始数据) tfInfoEx.dwFlags = HSE_TF_FLAG_USE_EX_INFO | HSE_TF_FLAG_SEND_RAW_DATA; tfInfoEx.hFile = hBigFile; // 拆分64位偏移到两个DWORD成员 tfInfoEx.Offset = static_cast<DWORD>(fileOffset & 0xFFFFFFFF); tfInfoEx.OffsetHigh = static_cast<DWORD>((fileOffset >> 32) & 0xFFFFFFFF); tfInfoEx.BytesToWrite = imageSize; // 按需设置响应状态码等 tfInfoEx.pszStatusCode = "200 OK"; tfInfoEx.pszStatusReason = "OK"; // 调用ServerSupportFunction发送文件片段 BOOL success = pECB->ServerSupportFunction( pECB->ConnID, HSE_REQ_TRANSMIT_FILE, &tfInfoEx, NULL, NULL );
另外要确保你的大文件句柄是支持大文件访问的——打开文件时使用CreateFile,不要设置FILE_FLAG_NO_BUFFERING以外的限制(Windows XP及以上系统默认支持大文件)。
2. 退而求其次:内存中转发送
如果你的目标IIS版本低于6.0(不支持HSE_TF_INFO_EX),可以先把大文件中的图片片段读取到内存缓冲区,再用异步方式发送缓冲区数据。虽然失去了TRANSMIT_FILE的零拷贝优势,但因为你的图片小于100KB,内存开销在可接受范围内:
// 读取图片到内存 BYTE* pImageBuffer = new BYTE[imageSize]; OVERLAPPED overlapped = {0}; overlapped.Offset = static_cast<DWORD>(fileOffset & 0xFFFFFFFF); overlapped.OffsetHigh = static_cast<DWORD>((fileOffset >> 32) & 0xFFFFFFFF); BOOL readSuccess = ReadFile( hBigFile, pImageBuffer, imageSize, NULL, &overlapped ); // 异步发送内存数据 if (readSuccess || GetLastError() == ERROR_IO_PENDING) { // 等待读取完成(或者用IOCP处理异步完成) WaitForSingleObject(overlapped.hEvent, INFINITE); // 设置响应头 pECB->ServerSupportFunction( pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, (LPVOID)"200 OK", (LPDWORD)strlen("image/jpeg"), (LPVOID)"image/jpeg" ); // 发送缓冲区数据 DWORD bytesSent = 0; pECB->WriteClient( pECB->ConnID, pImageBuffer, &imageSize, HSE_IO_ASYNC ); delete[] pImageBuffer; }
这个方案需要注意内存管理,避免内存泄漏,同时如果并发请求量大,要考虑内存池优化。
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

