2014-02-20 2 views
1

У меня возникли проблемы с серверной программой, используя библиотеку boost :: asio.Ошибка сегментации с boost :: asio, асинхронный udp-сервер с deadline_timer

Класс Сервер очень похож на тот, представленный в форсированный ASIO учебник "asynchronous udp-server"

Класс имеет публичный метод («sendMessageTo»), который вызывается сообщением - объект процессора, то здесь ошибки сегментации возникает, если метод вызывается потоком deadline_timer. Это происходит с вызовом новой std :: string (msg, len), это меня озадачивает. msg содержит то, что он должен содержать, и len тоже.

void Server::sendMessageTo(const char* msg, size_t len, udp::endpoint to) 
{ 
    boost::shared_ptr<std::string> message(new std::string (msg,len)); 
    socket.async_send_to(boost::asio::buffer(*message), to, 
         boost::bind(&Server::handleSend, this, message, 
            boost::asio::placeholders::error, 
            boost::asio::placeholders::bytes_transferred)); 
} 

Когда метод «sendMessageTo» вызывается с первой попытки, то все работает отлично: Это называется позже в том же потоке, который открывается с помощью метода «handleReceive» класса сервера.

Мой объект обработки сообщений - это своего рода машина состояний, которая поддерживает удаленную конечную точку, а в некоторых состояниях периодически хочет отправить некоторые сообщения udp обратно в конечную точку. Для этого используется asio :: deadline_timer. Таймер таймера создается с тем же io_service, udp-server работает. Когда таймер отменяется в первый раз, метод state_handling внутри объекта message_processor вызывает метод sendMessageTo, при котором возникает ошибка сегментации. Все аргументы «sendMessageTo» действительны и содержат ожидаемые значения.

Конструктор головки моего сообщения, процессор класса (называемый Transaction)

Transaction::Transaction(ClientReference *cli, ServerReference *serv) 
    : timer(*(serv->getIOService()), boost::posix_time::milliseconds(TRANSACTION_THREAD_SLEEP_MILLISEC)), 
     clientEndpoint(serv->getEndpoint()) 

таймер является ASIO :: deadline_timer объект, и clientEndpoint является УДП :: конечная точка

ответ сервера посылается внутри метода транзакции :: runThread()

server->sendMessageTo(&encryptedMsgBuf[0], size, clientEndpoint); 

encryptedMsgBuf представляет собой буфер массив символов, который хранит зашифрованное сообщение, и оно является частью Tra nsaction - объект.

в конце метода транзакции :: runThread() для deadline_timer называется на метод runThread(), чтобы активировать его, пока конечное состояние не будет достигнуто:

if (state != done && state != expired) 
    timer.async_wait(boost::bind(&Transaction::runThread, this)); 

Спасибо преимущество.

+0

Что такое 'Server :: handleSend()' похоже? –

+0

Возможно, вам стоит показать больше кода. SSCCE приходит на ум – sehe

+0

@Stefan 'Server :: handleSend()' просто пуст обработчик обратного вызова. @sehe, я работал над SSCCE, но пока что узнал, какова может быть основная проблема. Обновление вопроса, возможно, SSCCE последует, если необходимо. – mburrows2703

ответ

1

Я не уверен на этом на 100%, так как я не могу локально воспроизвести вашу ошибку из того, что вы опубликовали, но я сильно подозреваю, что ваша проблема связана с областью определения переменной строки сообщения. У меня были некоторые проблемы с boost::shared_ptr в прошлом, где shared_ptr был разрушен раньше, чем ожидалось. Если это так, то shared_ptr message может быть разрушено в конце вызова до Server::sendMessageTo(), и когда асинхронный tranmission фактически пытается запустить, эта память была освобождена, вызвав segfault.

В общем, мне нравится сохранять буферы, которые я фактически передаю и получаю как частные члены моего сервера и классов клиентов, чтобы убедиться, что они статически охвачены и не исчезнут на мне неожиданно на полпути через передавать или получать. Это может стоить немного в памяти, но я нахожу, что это дает мне много спокойствия. Если этот подход не даст вам никакой радости, сообщите мне, и я увижу, могу ли я воспроизвести ошибку локально.(В настоящий момент мои попытки «локального воспроизведения» состоят в том, что я взломал старый «сервер-клиент с использованием ASIO», чтобы выделить буфер TX, как вы указали выше, а затем перетащите некоторую память, чтобы, если TX пытается сделать дальше

+0

Здравствуйте, спасибо за ваш ответ, так как это только для личной программы я отложил ее на некоторое время. Проблема не в том, что вы предложили, потому что сообщение все еще действует. Я получаю ошибку segfault, когда я пытаюсь получить доступ к t он ссылается на асинхронный вызов 'Transaction :: runThread', хотя я создал его с помощью copy-constructor. – mburrows2703

Смежные вопросы