mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Use async_write to prevent locks if receiver is too slow
This commit is contained in:
		| @@ -105,17 +105,44 @@ void NetworkConnection::onPacketReceived(const boost::system::error_code & ec, u | |||||||
| void NetworkConnection::sendPacket(const std::vector<std::byte> & message) | void NetworkConnection::sendPacket(const std::vector<std::byte> & message) | ||||||
| { | { | ||||||
| 	std::lock_guard<std::mutex> lock(writeMutex); | 	std::lock_guard<std::mutex> lock(writeMutex); | ||||||
|  | 	std::vector<std::byte> headerVector(sizeof(uint32_t)); | ||||||
|  | 	uint32_t messageSize = message.size(); | ||||||
|  | 	std::memcpy(headerVector.data(), &messageSize, sizeof(uint32_t)); | ||||||
|  |  | ||||||
| 	boost::system::error_code ec; | 	bool messageQueueEmpty = dataToSend.empty(); | ||||||
|  | 	dataToSend.push_back(headerVector); | ||||||
| 	// create array with single element - boost::asio::buffer can be constructed from containers, but not from plain integer |  | ||||||
| 	std::array<uint32_t, 1> messageSize{static_cast<uint32_t>(message.size())}; |  | ||||||
|  |  | ||||||
| 	boost::asio::write(*socket, boost::asio::buffer(messageSize), ec ); |  | ||||||
| 	if (message.size() > 0) | 	if (message.size() > 0) | ||||||
| 		boost::asio::write(*socket, boost::asio::buffer(message), ec ); | 		dataToSend.push_back(message); | ||||||
|  |  | ||||||
| 	//Note: ignoring error code, intended | 	if (messageQueueEmpty) | ||||||
|  | 		doSendData(); | ||||||
|  | 	//else - data sending loop is still active and still sending previous messages | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NetworkConnection::doSendData() | ||||||
|  | { | ||||||
|  | 	if (dataToSend.empty()) | ||||||
|  | 		throw std::runtime_error("Attempting to sent data but there is no data to send!"); | ||||||
|  |  | ||||||
|  | 	boost::asio::async_write(*socket, boost::asio::buffer(dataToSend.front()), [self = shared_from_this()](const auto & error, const auto & ) | ||||||
|  | 	{ | ||||||
|  | 		self->onDataSent(error); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NetworkConnection::onDataSent(const boost::system::error_code & ec) | ||||||
|  | { | ||||||
|  | 	std::lock_guard<std::mutex> lock(writeMutex); | ||||||
|  | 	dataToSend.pop_front(); | ||||||
|  | 	if (ec) | ||||||
|  | 	{ | ||||||
|  | 		logNetwork->error("Failed to send package: %s", ec.message()); | ||||||
|  | 		// TODO: Throw? | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!dataToSend.empty()) | ||||||
|  | 		doSendData(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void NetworkConnection::close() | void NetworkConnection::close() | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ class NetworkConnection : public INetworkConnection, public std::enable_shared_f | |||||||
| 	static const int messageHeaderSize = sizeof(uint32_t); | 	static const int messageHeaderSize = sizeof(uint32_t); | ||||||
| 	static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input | 	static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input | ||||||
|  |  | ||||||
|  | 	std::list<std::vector<std::byte>> dataToSend; | ||||||
| 	std::shared_ptr<NetworkSocket> socket; | 	std::shared_ptr<NetworkSocket> socket; | ||||||
| 	std::mutex writeMutex; | 	std::mutex writeMutex; | ||||||
|  |  | ||||||
| @@ -27,6 +28,9 @@ class NetworkConnection : public INetworkConnection, public std::enable_shared_f | |||||||
| 	void onHeaderReceived(const boost::system::error_code & ec); | 	void onHeaderReceived(const boost::system::error_code & ec); | ||||||
| 	void onPacketReceived(const boost::system::error_code & ec, uint32_t expectedPacketSize); | 	void onPacketReceived(const boost::system::error_code & ec, uint32_t expectedPacketSize); | ||||||
|  |  | ||||||
|  | 	void doSendData(); | ||||||
|  | 	void onDataSent(const boost::system::error_code & ec); | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket); | 	NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user