【发布时间】:2015-12-30 06:45:37
【问题描述】:
我是 Winsock 的新手。我正在编写一个 HTTP 服务器,我的目标是通过读取和发送块来发送一个大文件。为了优化这个过程,我尝试使用非阻塞套接字,在发送当前块的同时从磁盘读取下一个块。
我现在的问题是,即使缓冲区看起来应该已满,并且我的函数过早地从内存中删除相关数据,我也会收到一条 FD_WRITE 消息。我相信这会导致我的响应包含的数据少于它们应该包含的数据 send() 过早地停止发送,并且客户端(这是一个众所周知的)接收到大约 70% 的数据。当我使用阻塞套接字时,它可以正常工作,只是更长。
我尝试使用 Wget(一个简单的 HTTP 客户端)来更好地了解正在发生的事情。据我所知,当我在使用 send() 后检查错误时检测到 WSAEWOULDBLOCK 错误时,数据流会变薄。看起来在这些发送期间,并非所有数据都已发送。
当我在检查 FD_WRITE 消息后将睡眠时间设置为超过 2000 毫秒时,一切正常,因为它基本上归结为使用阻塞套接字。我还尝试将时间设置为 100-200 毫秒左右,但也失败了。事实上,FD_WRITE 的条件检查总是在进入循环之前返回有效。
WSAEVENT event = WSACreateEvent();
const int sendBufferSize = 1024 * 64;
int connectionSpeed = 5; //estimated, in MBytes/s
const int sleepTime = sendBufferSize / (connectionSpeed * 1024 * 1024);
size = 0;
const int bufSize = 1024 * 1024 * 35;
int lowerByteIndex = 0;
int upperByteIndex = bufSize;
size = bufSize;
int totalSIZE = 0;
unsigned char* p;
unsigned char* pt;
clock_t t = std::clock();
p = getFileBytesC(resolveLocalPath(path), size, lowerByteIndex, upperByteIndex);
lowerByteIndex += bufSize;
upperByteIndex += bufSize;
totalSIZE += size;
while (upperByteIndex <= fileSize + bufSize)
{
int ret = send(socket, (char*)p, size, 0);
pt = getFileBytesC(resolveLocalPath(path), size, lowerByteIndex, upperByteIndex);
totalSIZE += size;
lowerByteIndex += bufSize;
upperByteIndex += bufSize;
if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
{
while (SOCKET_ERROR == WSAEventSelect(socket, event, FD_WRITE))
{
Sleep(50);
}
}
Sleep(sleepTime); //should be around 30-50ms. Wait for the buffer to be empty
delete[] p;
p = pt;
std::cout << std::endl << (std::clock() - t) / (double)CLOCKS_PER_SEC;
}
send(socket, (char*)p, size, 0);
delete[] p;
std::cout << std::endl << (std::clock() - t) / (double)CLOCKS_PER_SEC ;
if (totalSIZE == fileSize) std::cout << std::endl << "finished transfer. UBI=" << upperByteIndex;
else
{
std::cout << std::endl << "ERROR: finished transfer\r\nBytes read=" << totalSIZE;
}
Sleep(2000);
closeSocket(socket);
【问题讨论】: