Как отлаживать Не удается закрыть неинициализированное исключение Msg FaultException?

Мое приложение аварийно завершает работу из-за необработанного исключения "Не удается закрыть неинициализированное сообщение". Вероятно, это связано с доступом к сокету из нескольких потоков.

И у меня есть проблема с отладкой этой проблемы, потому что, когда я просматриваю свой код, весь доступ к сокету осуществляется в потоке опроса - либо напрямую в обработчике событий ReceiveReady (который запускается в потоке опроса по определению, насколько я понимаю), либо в созданном вручную Task ( new Task(...)), а затем запущен в потоке опроса (task.Start(poller)). Поэтому я не вижу места, где это могло бы произойти.

Вторая проблема заключается в том, что это необработанное исключение - я оборачиваю все отправку/получение в try-catch, но исключение происходит где-то снаружи.

Я ищу способы, как эффективно отладить его и определить место в моем коде, которое ведет себя неправильно.


Примеры кода — как я уже писал, я использую только два «шаблона»:

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

 private async void OnMessageReceiveReady(object sender, NetMQSocketEventArgs args)
 {
     NetMQSocket socket = args.Socket;

     NetMQMessage mq_msg = socket.ReceiveMultipartMessage();
     ...

Переключение на поток опроса из произвольного потока:

Task sending = new Task(() =>
{
    foreach (NetMQFrame address in mq_envelope)
        socket.SendMoreFrame(address.ConvertToString());

    socket.SendFrame(response_data);
});
sending.Start(this.sharedPoller);
await sending.ConfigureAwait(false);

person astrowalker    schedule 26.07.2017    source источник
comment
Можете ли вы показать нам часть соответствующего кода (насколько это возможно)?   -  person mjwills    schedule 26.07.2017
comment
Заблокирован ли код там, где вы читаете/записываете полученные данные? Обработчик события ReceiveReady должен очень мало работать с данными. Он должен прочитать данные, поместить их в буфер и продолжить. Обработка буфера должна выполняться в другом потоке или в основном коде.   -  person jdweng    schedule 26.07.2017
comment
@mjwills, я обновил вопрос - я использую этот код несколько раз, вот и все.   -  person astrowalker    schedule 26.07.2017
comment
@jdweng, ты имеешь в виду команду lock? Нет, события запускаются в потоке опроса, поэтому в данный момент времени может быть запущен только один, верно? Спасибо за совет, но он больше касается производительности, а не многопоточного выполнения. Возможно ли получить такое исключение, потому что код ReceiveReady занимает немного больше времени?   -  person astrowalker    schedule 26.07.2017
comment
Дейтаграммы TCP имеют максимальный размер ~ 1500 байт. Вы можете получать дейтаграммы с нулевыми байтами (сообщение о сохранении активности), а дейтаграммы могут быть разделены на небольшие дейтаграммы и объединены маршрутизаторами и серверами. Таким образом, отправленные данные не всегда будут получены, поэтому принимающий синтаксический анализатор должен быть достаточно умным, чтобы обрабатывать дробные сообщения. Мой метод ReceiveReady. Я просто добавляю необходимые данные в объект List‹string›. Затем синтаксический анализатор удаляет один сообщение за раз из List‹string›. Данные Ascii, которые мой синтаксический анализатор будет считывать из List‹string›, пока не найдет первое возвращенное. Затем удаляет строку в заблокированном коде, поэтому RxReady заблокирован.   -  person jdweng    schedule 26.07.2017
comment
@jdweng, впервые слышу, что ZMQ может доставлять часть сообщения, насколько я знаю, он разработан по принципу «все или ничего» (на некоторых сокетах может произойти падение из-за достижения HWM, но это другая история). В любом случае, это замечание побочного характера - я не понимаю, как эта проблема имеет отношение к отладке исключения, о котором я писал.   -  person astrowalker    schedule 26.07.2017
comment
Это указано в спецификации RFC для TCP. Мой ответ не был напрямую связан с отладкой, но если архитектура кода не была разработана для обработки всех возможных ситуаций, код необходимо переработать. Реализация событий Microsoft использует таймеры для передавать данные между буферами, и эти таймеры не синхронизированы с полученными данными tcp. При многоскачковых соединениях сообщения могут идти по разным маршрутам. Брандмауэры используют переадресацию портов, которая также не синхронизируется с дейтаграммами. Реализация дейтаграмм может варьироваться в зависимости от поставщика, поэтому 1504 байта могут быть 1500 байт + 4 байта.   -  person jdweng    schedule 26.07.2017


Ответы (1)


К сожалению, я не нашел другого метода, кроме проб и ошибок и большего количества журналов.

И проблема заключалась в удалении сокетов - у меня запущен опросчик (общий), и я пытался использовать сокет Remove и Dispose, однако обнаружил, что эти два метода асинхронны.

В качестве решения я группирую Remove и Dispose вместе в отдельную задачу, а затем планирую ее запуск в опроснике. Имея на руках task, я могу вызвать на нем Wait, и таким образом я достигну блокирующего, синхронного поведения в своем Dispose.

person astrowalker    schedule 27.07.2017