我正在使用boost asio编写TCP服务器 - 客户端对。它非常简单和同步。
服务器应该通过对通过TCP传输数据包的函数的几次递归调用来传输大量二进制数据。客户端通过递归函数执行模拟,读取和附加数据,该函数从套接字读取传入的数据包。
然而,在接收此数据的过程中,大多数时候(大约80%)客户端突然停止递归,总是在其中一个读取调用之前(如下所示)。鉴于在递归之后还有其他一些语句和函数调用,它不应该能够这样做。
size_t bytes_transferred = m_socket.read_some(boost::asio::buffer(m_fileReadBuffer, m_fileReadBuffer.size()));
m_fileReadBuffer是一个char :: boost数组,大小为4096(虽然我已尝试过其他缓冲格式但没有成功)。
绝对没有办法想象推断为什么会发生这种情况。
另外,请注意服务器始终成功发送所有数据,这一点非常重要。最重要的是,问题总是发生在传输的最后:我可以发送8000个字节,当传输大约6000或7000个字节时它会退出,我可以发送8000000个字节,它会在7996000字节之后退出已被转移。
我可以提供任何必要的代码,我只是不知道问题出在哪里。下面是客户端上的递归读取函数:
void TCP_Client::receive_volScan_message()
{
try
{
//If the transfer is complete, exit this loop
if(m_rollingSum >= (std::streamsize)m_fileSize)
{
std::cout << "File transfer complete!\n";
std::cout << m_fileSize << " "<< m_fileData.size() << "\n\n";
return;
}
boost::system::error_code error;
//Transfer isn't complete, so we read some more
size_t bytes_transferred = m_socket.read_some(boost::asio::buffer(m_fileReadBuffer, m_fileReadBuffer.size()));
std::cout << "Received " << (std::streamsize)bytes_transferred << " bytes\n";
//Copy the bytes_transferred to m_fileData vector. Only copies up to m_fileSize bytes into m_fileData
if(bytes_transferred+m_rollingSum > m_fileSize)
{
//memcpy(&m_fileData[m_rollingSum], &m_fileReadBuffer, m_fileSize-m_rollingSum);
m_rollingSum += m_fileSize-m_rollingSum;
}
else
{
// memcpy(&m_fileData[m_rollingSum], &m_fileReadBuffer, bytes_transferred);
m_rollingSum += (std::streamsize)bytes_transferred;
}
std::cout << "rolling sum: " << m_rollingSum << std::endl;
this->receive_volScan_message();
}
catch(...)
{
std::cout << "whoops";
}
}
作为建议,我尝试在客户端和服务器上将递归循环更改为for循环。不知何故,这个问题仍然存在。唯一的区别是现在不是在前面提到的read_some调用之前退出0,而是在其中一个for循环块的末尾退出0,就在它开始执行另一个for循环传递之前。
编辑:事实证明,每当我在IDE上以调试模式构建客户端时,都不会发生错误。
答案 0 :(得分:0)
我还没有完全理解这个问题,但是我已经完全解决了这个问题。
问题的根源在于,在客户端上,如果服务器消息尚未到达,则boost::asio::read
调用进行主要退出,代码为0。这意味着一个简单的
while(m_socket.available() == 0)
{
;
}
在所有读取调用完全阻止问题之前。两者都处于调试和发布模式。
这很奇怪,因为我理解这些函数应该阻塞直到有东西要读,即使它们遇到错误也应该返回零。
我认为调试/发布差异的发生是因为m_readBuffer
在读取调用发生时没有初始化为任何内容。这使得read
调用返回某种形式的无声错误。在调试时,未初始化的变量会自动设置为NULL
,从而悄悄解决我的问题。
我不知道为什么在传输之后添加while循环会阻止此问题。在m_readBuffer设置并成功使用多次之后,传输的 end 通常都发生了原因。
最重要的是,我从未见过这种类型的&#34;崩溃&#34;之前,程序只是在随机位置使用代码0退出,没有抛出任何错误或异常。