gpt4 book ai didi

sockets - 使用 boost::asio::read_some 在 TCP/IP 中丢弃数据?

转载 作者:行者123 更新时间:2023-12-01 10:56:39 24 4
gpt4 key购买 nike

我已经使用 boost::asio 实现了一个 TCP 服务器。此服务器使用 basic_stream_socket::read_some 函数读取数据。我知道 read_some 不保证提供的缓冲区在返回之前会满。

在我的项目中,我发送由定界符分隔的字符串(如果有的话)。在客户端,我使用 WinSock::send() 函数发送数据。现在我的问题出在服务器端,我无法获取从客户端发送的所有字符串。我怀疑 read_some 正在接收一些数据并出于某种原因丢弃剩余数据。然后在下一个调用中再次调用它接收另一个字符串。

在 TCP/IP 中真的可行吗?

我尝试使用 async_receive 但这会耗尽我所有的 CPU,而且由于必须通过回调函数清理缓冲区,这会导致我的程序出现严重的内存泄漏。 (我正在使用 IoService::poll() 调用处理程序。与 async_read() 的调用速率相比,该处理程序的调用速率非常慢)。

我再次尝试使用免费函数 read 但这并不能解决我的目的,因为它会因我提供的缓冲区大小而阻塞太多时间。

我以前的服务器实现是使用 WinSock API,我可以使用 WinSock::recv() 接收所有数据。请给我一些线索,以便我可以使用 boost::asio 接收完整的数据。

这是我的服务器端线程循环

void 
TCPObject::receive()
{
if (!_asyncModeEnabled)
{
std::string recvString;
if ( !_tcpSocket->receiveData( _maxBufferSize, recvString ) )
{
LOG_ERROR("Error Occurred while receiving data on socket.");
}
else
_parseAndPopulateQueue ( recvString );
}
else
{
if ( !_tcpSocket->receiveDataAsync( _maxBufferSize ) )
{
LOG_ERROR("Error Occurred while receiving data on socket.");
}
}
}

TCPSocket 中的 receiveData()

bool 
TCPSocket::receiveData( unsigned int bufferSize, std::string& dataString )
{
boost::system::error_code error;
char *buf = new char[bufferSize + 1];
size_t len = _tcpSocket->read_some( boost::asio::buffer((void*)buf, bufferSize), error);
if(error)
{
LOG_ERROR("Error in receiving data.");
LOG_ERROR( error.message() );
_tcpSocket->close();
delete [] buf;
return false;
}
buf[len] ='\0';
dataString.insert( 0, buf );
delete [] buf;
return true;
}

在 TCP 套接字中接收数据异步

bool 
TCPSocket::receiveDataAsync( unsigned int bufferSize )
{
char *buf = new char[bufferSize + 1];

try
{
_tcpSocket->async_read_some( boost::asio::buffer( (void*)buf, bufferSize ),
boost::bind(&TCPSocket::_handleAsyncReceive,
this,
buf,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred) );
//! Asks io_service to execute callback
_ioService->poll();
}
catch (std::exception& e)
{
LOG_ERROR("Error Receiving Data Asynchronously");
LOG_ERROR( e.what() );
delete [] buf;
return false;
}

//we dont delete buf here as it will be deleted by callback _handleAsyncReceive
return true;
}

异步接收处理程序

void 
TCPSocket::_handleAsyncReceive(char *buf, const boost::system::error_code& ec, size_t size)
{
if(ec)
{
LOG_ERROR ("Error occurred while sending data Asynchronously.");
LOG_ERROR ( ec.message() );
}
else if ( size > 0 )
{
buf[size] = '\0';
emit _asyncDataReceivedSignal( QString::fromLocal8Bit( buf ) );
}
delete [] buf;
}

客户端发送数据函数。

sendData(std::string data)
{
if(!_connected)
{
return;
}

const char *pBuffer = data.c_str();

int bytes = data.length() + 1;

int i = 0,j;
while (i < bytes)
{
j = send(_connectSocket, pBuffer+i, bytes-i, 0);

if(j == SOCKET_ERROR)
{
_connected = false;
if(!_bNetworkErrNotified)
{
_bNetworkErrNotified=true;
emit networkErrorSignal(j);
}
LOG_ERROR( "Unable to send Network Packet" );
break;
}
i += j;
}
}

最佳答案

Boost.Asio 的 TCP 功能被很好地使用,所以我会犹豫是否怀疑它是问题的根源。在大多数数据丢失的情况下,问题出在应用程序代码上。

在这种情况下,接收方代码有问题。发件人正在使用 \0 分隔字符串.但是,在单个读取操作中读取多个字符串的情况下,接收方无法正确处理定界符,如 string::insert()将导致截断 char*当它到达第一个定界符时。

例如,发件人写了两个字符串"Test string\0""Another test string\0" .在 TCPSocket::receiveData() ,接收者读取 "Test string\0Another test string\0"进入buf . dataString然后填充 dataString.insert(0, buf) .这个特殊的重载将复制到分隔符,所以 dataString将包含 "Test string" .要解决此问题,请考虑使用 string::insert()需要插入字符数的重载:dataString.insert(0, buf, len) .

关于sockets - 使用 boost::asio::read_some 在 TCP/IP 中丢弃数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14833882/

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