Программирование сокетов: сообщение не проходит проверку. Кто-нибудь знает фантом причины?

Сейчас у меня есть коммуникационная инфраструктура, состоящая из клиента и сервера.

Клиент подключается к серверу, используя стандартные сокеты TCP.

У меня есть структура сообщения, которая выглядит следующим образом:

4 bytes -- Message size
n bytes -- Message
4 bytes -- CRC32 checksum

Одним из требований является то, что для того, чтобы сообщение было действительным, оно должно пройти проверку CRC32 на другом конце соединения, клиент или сервер обрабатывают сообщения одинаково.

Если сообщение не проходит проверку CRC32, соединение разрывается и устанавливается новое соединение.

Мой вопрос: почему, черт возьми, я получаю сбои CRC32 случайным образом?

Без видимой причины, даже когда клиент и сервер на одном компьютере используют петлевой адрес (127.0.0.1).

Я думал, что даже если я запрограммировал отказоустойчивость на случай злонамеренной третьей стороны или чего-то еще, я никогда не увижу разрыва соединения во время моих тестов.


person Paulo Santos    schedule 07.07.2011    source источник
comment
Мое лучшее предположение, что в вашем коде контрольной суммы есть ошибка. Можете ли вы показать нам минимальный пример кода?   -  person tjollans    schedule 07.07.2011
comment
Я бы предположил, что есть ошибка либо при чтении/записи (например, при условии, что recv всегда возвращает точную требуемую длину данных, аналогичную для send), либо ошибка в вашем коде, проверяющем/создающем CRC. публикация некоторого кода будет иметь большое значение для прояснения этого и поможет нам помочь вам.   -  person Hasturkun    schedule 07.07.2011


Ответы (2)


Вы не показали никакого кода, поэтому я могу только догадываться.

  • Вы читаете байты из сокетов, не проверяя прочитанный размер. TCP — это протокол, ориентированный на поток, поэтому нет никаких гарантий относительно количества операций чтения, которые необходимо выполнить для отправки всех данных. Единственная гарантия состоит в том, что после неопределенного количества операций чтения, используя неопределенное количество сегментов, вы получите все октеты по порядку.

  • Ваши функции контрольной суммы не работают для некоторых входных данных, потому что они неверны

Первое, вероятно, то, что происходит. Вы читаете некоторые данные, а recv/read возвращает с меньшим количеством прочитанных байтов, чем вы ожидаете.

Кстати, вы понимаете, что вы пытаетесь сделать правильно?

  • Кадр Ethernet имеет поле CRC-32.
  • Пакет IPv4 имеет контрольную сумму заголовка 16b.
  • Сегмент TCP имеет 16-битную контрольную сумму, охватывающую заголовок, данные и некоторые
  • Ваши данные также будут иметь CRC-32

Вы же понимаете, что это лишнее?

person cnicutar    schedule 07.07.2011
comment
+1 за наблюдение за избыточностью. Я работал с протоколами, которые включали какой-то кадрирующий байт, отмечающий конец или начало сообщения. Это позволяет вам убедиться, что отправитель сообщения не отправил поврежденное сообщение (сообщение, не соответствующее MessageSize). Вероятно, было бы полезно подтвердить, что сообщение действительно, не прибегая к вычислению CRC. - person Lou; 07.07.2011

Кстати, правильный способ проверить контрольную сумму у получателя — вычислить ее по всему сообщению и контрольной сумме, вместе рассматриваемой как более длинное сообщение. Результат должен быть нулевым. Таким образом, вы включаете в расчет саму контрольную сумму. Неправильный способ сделать это — вычислить контрольную сумму по сообщению, исключая контрольную сумму, а затем сравнить с полученной контрольной суммой.

person user207421    schedule 08.07.2011
comment
Не могли бы вы рассказать, как это должно работать? Потому что я никогда не слышал об этом, и мне любопытно :) - person fresskoma; 08.07.2011
comment
Что конкретно не так с неправильным способом, который вы описали? Мне кажется, что любой метод будет работать (где work == генерирует ошибку несоответствия контрольной суммы, если данные повреждены), но я, вероятно, упускаю некоторые детали. - person Jeremy Friesner; 08.07.2011
comment
Контрольная сумма определяется как остаток XOR над сообщением, поэтому ее включение в расчет должно дать ноль. Это превосходный метод по причине, которую я указал: он не предполагает, что сама контрольная сумма была передана правильно. Можно представить искажения, которые искажают сообщение и контрольную сумму совместимым образом: это их ловит. - person user207421; 09.07.2011