Fir*_*cer 26 c++ sockets network-programming tcp boost-asio
有时boost :: asio似乎在我想要之前断开连接,即在服务器正确处理断开连接之前.我不确定这是怎么可能的,因为客户端似乎认为它完全发送了消息,但是当服务器发出错误时它甚至没有读取消息头...在测试期间,这种情况可能只发生在5次中,服务器接收客户端关闭消息,并干净地断开客户端.
错误:"远程主机强行关闭现有连接"
客户端断开连接:
void disconnect()
{
boost::system::error_code error;
//just creates a simple buffer with a shutdown header
boost::uint8_t *packet = createPacket(PC_SHUTDOWN,0);
//sends it
if(!sendBlocking(socket,packet,&error))
{
//didnt get here in my tests, so its not that the write failed...
logWrite(LOG_ERROR,"server",
std::string("Error sending shutdown message.\n")
+ boost::system::system_error(error).what());
}
//actaully disconnect
socket.close();
ioService.stop();
}
bool sendBlocking(boost::asio::ip::tcp::socket &socket,
boost::uint8_t *data, boost::system::error_code* error)
{
//get the length section from the message
boost::uint16_t len = *(boost::uint16_t*)(data - 3);
//send it
asio::write(socket, asio::buffer(data-3,len+3),
asio::transfer_all(), *error);
deletePacket(data);
return !(*error);
}
Run Code Online (Sandbox Code Playgroud)
服务器:
void Client::clientShutdown()
{
//not getting here in problem cases
disconnect();
}
void Client::packetHandler(boost::uint8_t type, boost::uint8_t *data,
boost::uint16_t len, const boost::system::error_code& error)
{
if(error)
{
//error handled here
delete[] data;
std::stringstream ss;
ss << "Error recieving packet.\n";
ss << logInfo() << "\n";
ss << "Error: " << boost::system::system_error(error).what();
logWrite(LOG_ERROR,"Client",ss.str());
disconnect();
}
else
{
//call handlers based on type, most will then call startRead when
//done to get the next packet. Note however, that clientShutdown
//does not
...
}
}
void startRead(boost::asio::ip::tcp::socket &socket, PacketHandler handler)
{
boost::uint8_t *header = new boost::uint8_t[3];
boost::asio::async_read(socket,boost::asio::buffer(header,3),
boost::bind(&handleReadHeader,&socket,handler,header,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
void handleReadHeader(boost::asio::ip::tcp::socket *socket, PacketHandler handler,
boost::uint8_t *header, size_t len, const boost::system::error_code& error)
{
if(error)
{
//error "thrown" here, len always = 0 in problem cases...
delete[] header;
handler(0,0,0,error);
}
else
{
assert(len == 3);
boost::uint16_t payLoadLen = *((boost::uint16_t*)(header + 0));
boost::uint8_t type = *((boost::uint8_t*) (header + 2));
delete[] header;
boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen];
boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen),
boost::bind(&handleReadBody,socket,handler,
type,payLoad,payLoadLen,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
}
void handleReadBody(ip::tcp::socket *socket, PacketHandler handler,
boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len,
size_t readLen, const boost::system::error_code& error)
{
if(error)
{
delete[] payLoad;
handler(0,0,0,error);
}
else
{
assert(len == readLen);
handler(type,payLoad,len,error);
//delete[] payLoad;
}
}
Run Code Online (Sandbox Code Playgroud)
Gra*_*amS 27
我想你应该在打电话socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec)之前打电话到那里socket.close().
basic_stream_socket :: close状态的boost :: asio文档:
对于关于正常关闭连接套接字的可移植行为,请在关闭套接字之前调用shutdown().
这应确保正确取消套接字上的任何挂起操作,并在调用socket.close之前刷新任何缓冲区.
Wil*_*now 11
我试图用close()方法和shutdown()方法做到这一点
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec)
Run Code Online (Sandbox Code Playgroud)
关机方法是两者中最好的.但是,我发现使用ASIO套接字的析构函数是干净的方法,因为ASIO会为您完成所有操作.所以你的目标是让套接字超出范围.现在,您可以使用shared_ptr轻松完成此操作,并将shared_ptr重置为新的套接字或null.这将调用ASIO套接字的析构函数,生活是美好的.
也许这就是发生的事情:
我在你的读处理程序中看到,如果有错误,你永远不会检查你的关闭数据包是否存在.也许是.基本上我所说的可能是你的客户端有时能够在服务器有机会单独处理它们之前发送关闭和关闭数据包.