Передача данных через соединение TCP-IPv6 - PullRequest
1 голос
/ 26 декабря 2011

Я работаю над клиент-серверным приложением на C и на платформе Linux. Я пытаюсь добиться изменения идентификатора сокета через TCP-соединение как на клиенте, так и на сервере без потери данных, когда клиент отправляет данные из файла на сервер в главном потоке. Приложение является многопоточным, где другие потоки изменяют идентификатор сокета на основе некоторых глобальных установленных флагов.

Проблема: В приложении установлено два соединения с сокетом TCP по обоим путям: IPv4 и IPv6. Сначала я передаю файл через соединение TCP-IPv4 в основном потоке. Другой поток проверяет некоторые глобальные флаги и имеет доступ к идентификаторам сокетов, созданным для каждого протокола в основном потоке. Send и recv используют переменную указателя в своем вызове для указания идентификатора сокета, который будет использоваться для передачи данных. Данные передаются изначально через TCP-Ipv4. Как только глобальные флаги установлены и несколько других проверок сделаны, другой поток изменяет идентификатор сокета, используемый в вызове отправки, чтобы указать на сокет IPv6. Этот поток также заботится о передаче изменений между двумя хостами. Я получаю все данные по IPv4, переданные полностью перед переключением. Также я получаю данные, отправленные через Ipv6 после переключения идентификатора сокета. Но при передаче происходит потеря данных по соединению IPv6 (я использую переменную-указатель в функции отправки на стороне сервера send(*p_dataSocket.socket_id,sentence,p_size,0);, чтобы на лету изменить указатель на идентификатор сокета IPv6)

Ошибка после вызова recv и send на обеих сторонах соответственно говорит ESPIPE:Illegal seek, но эта ошибка существует даже до переключения. Так что я почти уверен, что это никак не связано с потерей данных

Я использую pselect() для проверки доступных данных для каждого сокета. Я могу как-то понять потерю данных при переключении (если не обрабатывается должным образом), но я не могу понять, почему потеря данных происходит при передаче после переключения. Я надеюсь, что мне ясно, в чем проблема. Я также проверил отправку данных индивидуально по каждому протоколу без переключения, и нет потери данных. Сначала я передаю данные по Ipv6, а затем переключаюсь на IPv4, потери не происходит. Также было бы очень полезно узнать, как исследовать эту проблему, кроме использования errno или netstat.

1 Ответ

1 голос
/ 26 декабря 2011

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

Есть несколько моментов, которые вы можете исследовать.

  • Прежде всего вы должны убедиться, что вы действительно отправляете потерянные данные. Добавьте запись в приложение на стороне сервера: поместите все, что вы передаете, с помощью send () в некоторый файл. Включите дополнительную информацию, такую ​​как:

    № пакета данных == 1234, * p_dataSocket.socket_id == 11, Data == "data_contents_here", всего 22 байта; send () return == 22 * ​​1011 *

Здесь важно следить за содержанием *p_dataSocket.socket_id. Убедитесь, что вы используете мьютекс или что-то подобное, потому что у вас есть поток, который регулярно читает содержимое socket_id, и другой поток, который периодически его меняет. Вы не гарантированы от получения неправильного значения с этого адреса, если ваши потоки не имеют монопольного доступа к нему во время чтения / записи. Это важно как для нормальной работы программы, так и для генерации отладочной информации.

Другая возможная проблема здесь - логика, которая выбирает sentence для отправки. Повреждение этой переменной может быть трудно отследить в многопоточной программе. Регистрация переданной информации поможет вам и здесь.

  • Используйте любой анализатор TCP, чтобы проверить, что в действительности передает стек TCP. Есть ли пакеты с потерянными данными? Если таких пакетов нет, попробуйте выяснить, какой вызов send () отвечал за отправку этих данных. Если эти пакеты существуют, проверьте принимающую сторону на наличие ошибок.

  • errno не должно использоваться отдельно. Его значение имеет смысл только тогда, когда вы получаете ошибочный возврат из функции. Попытайтесь выяснить, когда именно Errno становится ESPIPE. Это может произойти, когда любая из функций API возвращает что-то вроде -1 (зависит от функции). Когда вы узнаете, где это происходит, вы должны выяснить, что не так в этом конкретном фрагменте кода (отладчик - ваш друг). Помните, что поведение errno в многопоточной среде зависит от реализации вашей системы. Убедитесь, что вы используете опцию -pthread (gcc) или хотя бы компилируете с -D_REENTRANT, чтобы минимизировать риски.

  • Проверьте этот вопрос , чтобы получить некоторую информацию о возможной причине вашей ситуации с ошибкой == ESPIPE. Попробуйте некоторые методы отладки, как предлагается там. Errno значение ESPIPE дает подсказку, что вы неправильно используете дескрипторы файлов где-то в вашей программе. Может быть, где-то вы используете сокет fd как обычный файл или что-то в этом роде. Это может быть вызвано некоторым состоянием гонки (одновременный доступ к одному объекту из нескольких потоков).

...