gpt4 book ai didi

c++ - 使用 send() 和 FD_WRITE 的 Winsock

转载 作者:搜寻专家 更新时间:2023-10-31 00:59:39 24 4
gpt4 key购买 nike

我是 Winsock 的新手。我正在编写一个 HTTP 服务器,我的目标是通过读取和发送 block 来发送一个大文件。为了优化这个过程,我尝试使用非阻塞套接字,在发送当前 block 的同时从磁盘读取下一个 block 。

我现在的问题是,即使缓冲区似乎已满并且我的函数过早地从内存中删除了相关数据,我还是收到了 FD_WRITE 消息。我相信这会导致我的响应包含的数据少于它们应该发送的数据 send() 过早地停止发送并且客户端(这是一个众所周知的)接收了大约 70% 的数据。当我使用阻塞套接字时,它工作正常,只是更长了。

我尝试使用简单的 HTTP 客户端 Wget 来更好地了解正在发生的事情。据我所知,当我在使用 send() 后检查错误时检测到 WSAEWOULDBLOCK 错误时,数据流变薄了。看起来在这些发送期间,并非所有数据都已发送。

当我在检查 FD_WRITE 消息后将 sleep 时间设置为超过 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);

最佳答案

  1. 如果不将返回值存储在变量中,您就无法编写正确的非阻塞 send() 代码。它是实际发送的字节数。您不能假设整个缓冲区都是以非阻塞模式发送的。

  2. 如果 send() 返回 -1 且 WSAGetLastError() == WSAEWOULDBLOCK 或任何它是什么,那么 是时间必要时调用 WSASelect(),WSAEVENTSelect(),但要超时。否则,即如果它返回一个正计数,您应该只增加偏移量并减少发送量的长度,然后重复直到没有任何东西要发送。

  3. 你的 sleep 简直就是浪费时间。

但我会质疑整个方法。无论如何,在阻塞模式套接字上发送是异步的。您目前的方法几乎无济于事。只需以 block 的形式读取文件并以阻塞模式发送 block 。

关于c++ - 使用 send() 和 FD_WRITE 的 Winsock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32900692/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com