Birkaç istemciyle iletişim kurmak için boost ASIO kullanan bir sunucu uygulamam var. Sunucu uygulaması bir Linux sunucusunda çalışır ve istemciler Windows masaüstlerinde çalışır.
Mevcut tasarım çok iş parçacıklı olsa da, yalnızca bir boost ASIO thead (çalışır boost::asio::io_context
). Boost ASIO iş parçacığı yalnızca okuma, yazma ve bazı seyrek gönderimden sorumludur. Okuma kullanılarak yapılır boost::asio::async_read
ancak elde edilen mesajı kopyalar, böylece başka bir iş parçacığı işleme işini yapabilir. Yazma kullanılarak yapılır boost::asio::write
ancak mesaj zaten kopyalandı ve boost ASIO iş parçacığına aktarıldı
Çoğu durumda, bir istemci boost ASIO bağlantısını kestiğinde bir hata atar, ilişkili soketi kapatırım ve diğer soketler çalışmaya devam eder. Ancak, bir istemcinin Windows masaüstünde elektrik kesintisi varsa boost::asio::write
onlara yazıyor mu, o zaman boost bir sorun algılamıyor ve askıda kalıyor mu boost::asio::write
. Bazen yaklaşık 20 dakika askıda kalıyor ve sunucu bu süre zarfında diğer istemcilerle iletişim kuramıyor
Çevrimiçi okuduklarımdan, boost asıo'nun yazarlarının bir zaman aşımı parametresi sunma niyeti yoktur. SO_SNDTİMEO'YU 5 saniyeye ayarlamayı denedim, ancak bunun yazma askıda kalması üzerinde herhangi bir etkisi olmadı. Şu an itibariyle sorunu çözmek için en iyi tahminim, her sokete farklı bir iş parçacığı vermektir, böylece bir istemci diğer istemcileri kaldıramaz. Bundan daha iyi seçenekler var mı? Eğer her soket kendi iş parçacığı ver yaparsam bir ihtiyacım var demek boost::asio::io_context
yazma askıda kalmasını önlemek için iş parçacığı başına mı?
Düzenleme: Yorumları gördükten sonra çağıran işlevi yeniden yapmayı denedim boost::asio::write
ile boost::asio::async_write
. ÖYLE ama yine de basitleştirilmiş bir kod var aşağıda Genel değiştirmek ne gösterir :
Başlangıçta ile boost::asio::write
:
inline void MessagingServer::writeMessage(
GuiSession* const a_guiSession,
const PB::Message& a_msg
) {
boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
// I removed code that writes a_msg's bytes into m_guiIoWriteBuf
// and sets totalSize to simplify for SO
boost::system::error_code error;
boost::asio::write(a_guiSession->m_guiIoGsSocket, boost::asio::buffer(m_guiIoWriteBuf, totalSize), error);
if (UNLIKELY(error))
ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << error.message();
});
}
İle yeniden boost::asio::async_write
:
inline void MessagingServer::writeMessage(
GuiSession* const a_guiSession,
const PB::Message& a_msg
) {
a_guiSession->m_tempMutex.lock();
boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
// I removed code that writes a_msg's bytes into m_guiIoWriteBuf
// and sets totalSize to simplify for SO
boost::asio::async_write(
a_guiSession->m_guiIoGsSocket,
boost::asio::buffer(m_guiIoWriteBuf, totalSize),
[this, a_guiSession](const boost::system::error_code& a_error, std::size_t) {
if (UNLIKELY(a_error))
ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << a_error.message();
a_guiSession->m_tempMutex.unlock();
}
);
});
}
Kilit, yalnızca bir çağrıyı garanti etmek için ikinci kodda tanıtıldı boost::asio::async_write
bir zamanlar aktifti (bunu yapmanın daha etkili yolları olduğunun farkındayım, ancak bu test için daha basit). Bu kodların her ikisi de, istemci bir elektrik kesintisi olduğunda boost ASIO'YU asmakla aynı soruna sahiptir. Bununla birlikte, farklı şekillerde asılırlar, asenkron kod, asıo'nun diğer eylemleri gerçekleştirmesine izin verir, ancak asılı olan bir hata üretene kadar daha fazla yazmaz
Ayrı bir deney sırasında ayarlamayı denedim SO_KEEPALIVE
ancak bu aynı zamanda askıda kalma sorununu da çözmedi