Заполнение данных по TCP - PullRequest
       32

Заполнение данных по TCP

1 голос
/ 26 февраля 2012

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

я. Используйте структуру, как показано ниже, и заполните vst_pad для последнего отправленного пакета и проверьте его на стороне recv на наличие. Преимущество перед вторым вариантом заключается в том, что мне не нужно удалять флаг из фактических данных перед записью его в файл. Просто проверьте первый член структуры

typedef struct
   {
    /* String holding padding for last packet when socket is changed */
    char vst_pad[10];
    /* Pointer to data being transmitted */
    char *vst_data;
    //unsigned char vst_data[1];
   } st_packetData;

Проблема в том, что я должен сериализовать структуру при каждом вызове отправки. Также я не уверен, получу ли я всю структуру через TCP за один вызов recv, и поэтому мне приходится добавлять логику / накладные расходы, чтобы проверять это каждый раз. Я реализовал это до сих пор, но потом понял, что потоковый TCP может не гарантировать получение всей структуры за один вызов.

II. Используйте функцию наподобие strncat, чтобы добавить этот флаг в конце к последним отправляемым данным.

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

Это приложение будет использоваться для передачи больших объемов данных и, следовательно, будет хотеть добавить минимальные издержки при каждом вызове send / recv / read / write. Было бы очень полезно узнать, если есть лучший вариант, чем два выше или любой другой вариант, чтобы проверить получение последнего пакета. Программа многопоточная.

Редактировать: я не знаю общий размер файла, который я собираюсь отправить, но я отправляю фиксированный объем данных. То есть fgets считывает, пока не будет указан размер -1 или пока не встретится новая строка.

Ответы [ 5 ]

2 голосов
/ 26 февраля 2012

Знаете ли вы заранее размер данных, и требуется ли вам применять флаг окончания сообщения?

Поскольку я бы упростил конструкцию, добавьте 4-байтовый заголовок (при условии, что выне отправляет более 4 ГБ данных на сообщение), которое содержит ожидаемый размер сообщения.

Таким образом, вы анализируете первые 4 байта, вычисляете размер, а затем продолжаете вызывать recv, пока не получите столькоданные.

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

Еще одна проблема, не связанная с вашим решением 10-байтового пэда, - это то, что происходит, еслифактическое сообщение содержит 10 нулевых байтов - если вы дополняете его нулями?Вам нужно было бы экранировать 10 байтов нулей, иначе вы можете по ошибке обрезать сообщение.

Использование заголовка фиксированного размера и значения известного размера решит эту проблему.

1 голос
/ 26 февраля 2012

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

Нетрудно добавить в заголовок байт статуса, который может идентифицировать последний кусок.

Альтернативой является открытие другого соединения для передачи данных, потоковая передача всей сериализации и затем закрытие этого соединения для передачи данных (как это делает FTP).

1 голос
/ 26 февраля 2012

Для сообщения (пакета данных) сначала отправьте короткий (в сетевом порядке) размер, а затем данные.Это может быть достигнуто одним системным вызовом write.

На приемном конце просто read переберите короткое замыкание и верните его в порядок хостов (это позволит использовать другие процессоры в более позднем состоянии.может тогда read остальные данные.

0 голосов
/ 26 февраля 2012

Если это действительно последние данные, отправленные вашим приложением, используйте shutdown(socket, SHUT_WR); на стороне отправителя.

Это установит флаг FIN TCP, который сигнализирует, что поток отправителя-> получателя являетсянад.Получатель будет знать это, потому что его recv () вернет 0 (точно так же как условие EOF), когда все будет получено.Получатель по-прежнему может отправлять данные позже, а отправитель может их прослушивать, но он не может отправлять больше с использованием этого соединения.

0 голосов
/ 26 февраля 2012

Не могли бы вы использовать библиотеку сетевых коммуникаций с открытым исходным кодом, написанную на C #? Если это так, проверьте networkComms.net .

...