Итак, у меня есть этот код, который заботится о подтверждении команд с удаленных компьютеров, иногда (например, один раз в 14 дней или что-то в этом роде) следующая строка выдает исключение нулевой ссылки:
computer.ProcessCommandAcknowledgment( commandType );
Что меня действительно беспокоит, так это то, что я проверяю перед ним нулевую ссылку, поэтому у меня есть нет идея, что происходит. Вот полный метод того, чего он стоит:
public static void __CommandAck( PacketReader reader, SocketContext context )
{
string commandAck = reader.ReadString();
Type commandType = Type.GetType( commandAck );
Computer computer = context.Client as Computer;
if (computer == null)
{
Console.WriteLine("Client already disposed. Couldn't complete operation");
}
else
{
computer.ProcessCommandAcknowledgment( commandType );
}
}
Какие-нибудь подсказки?
Обновлено: ProcessCommandAcknowledgment:
public void ProcessCommandAcknowledgment( Type ackType )
{
if ( m_CurrentCommand.GetType() == ackType )
{
m_CurrentCommand.Finish();
}
}
Однопоточный / 2.0.50727.1433 / x86
Можете ли вы опубликовать подпись (и) для ProcessCommandAcknwoldgement?
Можете ли вы опубликовать трассировку стека исключения?





Возможно ли, что ReadString() возвращает ноль? Это приведет к сбою GetType. Возможно, вы получили пустой пакет? В качестве альтернативы, строка может не соответствовать типу, и поэтому commandType будет иметь значение null при дальнейшем использовании.
РЕДАКТИРОВАТЬ:
Вы проверили, что m_CurrentCommand не равен нулю при вызове ProcessCommandAcknowledgment?
Нет, nullref выбрасывается в выделенную мной строку, пакеты на 100% достоверны и полны. (хеш-контроль + они зашифрованы).
Кроме того, метод подтверждения команды никогда не может генерировать нулевую ссылку, поскольку он сравнивает данный тип с типом, привязанным к компьютеру, поэтому на самом деле сравнение с нулевым значением допустимо.
Никакая часть кода никогда не устанавливает для него значение null. В ctor по умолчанию используется Command.Invalid.
Исходя из предоставленной вами информации, совершенно невозможно, чтобы в этом месте возникла пустая ссылка. Итак, следующий вопрос: «Как узнать, что конкретная строка создает исключение NullReferenceException?» Вы используете отладчик или информацию о трассировке стека? Вы проверяете розничную или отладочную версию кода?
Если это отладчик, различные комбинации настроек, которые могут привести к тому, что отладчик появляться будет сообщать о NullRef в другом месте. Главное, что это может сделать, - это настройка Just My Code.
По моему опыту, я нашел самый надежный способ определить строку, в которой действительно возникает исключение, - это ...
У меня есть подробная трассировка стека PDB. Информация верна на 100%.
Я готов поспорить, что есть проблема с вашим кодом кадрирования TCP (если он у вас есть!)
«PacketReader», возможно, предполагает, что вы этого не сделаете. Потому что технически это называлось бы "FrameReader" или что-то подобное, если бы вы это сделали.
Если два задействованных компьютера находятся в локальной сети или что-то в этом роде, это, вероятно, объяснит 14-дневный интервал. Если бы вы попробовали это через Интернет, я уверен, что ваша частота ошибок будет гораздо более распространенной, особенно если бы была ограничена пропускная способность WAN.
Недействительные пакеты отбрасываются, а отправившие их клиенты отключаются. Сначала проверяется crc полезной нагрузки, затем пакеты распаковываются и, наконец, дешифруются. Если какой-либо из этих шагов не удается, клиент отключается.
Если у вас включена оптимизация, скорее всего, вы укажете совсем не то место, где это на самом деле происходит.
Нечто подобное случилось со мной несколько лет назад.
Что ж, он надежно работал с теми же настройками компилятора. Всегда указывал на то место, где была ошибка. Только в этом конкретном случае, похоже, есть проблема.
Или же возможная гонка потоков где-то, где контекст получает значение null другим потоком. Это также объясняет необычность ошибки.
Хорошо, на самом деле есть только несколько возможностей.
Каким-то образом ваш компьютерный справочник попадает под удар, когда вы вызываете эту рутину.
Что-то под вызовом вызывает ошибку разыменования нулевого указателя, но обнаруживается в этой строке.
Глядя на это, я очень подозреваю, что стек поврежден, что приводит к автоматическому искажению вашего computer. Проверьте подпрограмму / метод / функцию, вызывающую вокруг, с которой у вас возникли проблемы; в частности, убедитесь, что то, что вы превращаете в предмет «Компьютер», действительно соответствует вашим ожиданиям.
Спасибо, есть подсказки, как его отладить?
Это может быть сложно отладить. Я бы попробовал две вещи: (1) перехватить исключение нулевой ссылки в этом месте и получить как можно больше информации, когда это произойдет; (2) найдите код для вызовов этой подпрограммы и исследуйте код на каждом из них.
О, в этом обработчике исключений посмотрите, что действительно дает вам Console.client.
Что делают другие потоки?
Обновлено: вы упоминаете, что сервер является однопоточным, но другой комментарий предполагает, что эта часть является однопоточным. Если это так, у вас все еще могут быть проблемы с параллелизмом.
Суть здесь, я думаю, в том, что у вас либо проблема с многопоточностью, либо ошибка CLR. Вы можете догадаться, что мне кажется более вероятным.
Конечно, есть дюжина других потоков, делающих что-то полезное, с другой стороны, сетевой код является однопоточным. Кроме того, я работаю с локальной переменной, которая в этот момент никогда не может иметь значение NULL, если не используется сборка мусора или что-то еще.
@arul - Ваше резервное поле объявлено нестабильным? Вы снимаете блокировки, когда устанавливаете это поле? Могут быть несколько менее очевидные проблемы с параллелизмом.
Это локальная переменная, которая существует в стеке и не может быть объявлена как изменчивая.
Поле поддержки для Context.Client, возможно, должно быть изменчивым.
Объявление его нестабильным, вероятно, решило проблему, я имею в виду, с тех пор этого не происходило.
computer.ProcessCommandAcknowledgment( commandType );
Есть ли у вас отладочные символы, чтобы в это можно было войти?
Исключение нулевой ссылки могло быть вызвано ProcessCommandAcknowledgement и всплыло.
Ага. Кроме того, ProcessCommandAcknowledgement принимает нулевую команду.
Можете ли вы указать 1) несколько потоков (да / нет), 2) версию CLR и 3) архитектуру процессора