Неблокированный сокет последовательной передачи файлов - PullRequest
0 голосов
/ 03 марта 2012

Сервер, на котором я работаю (это многопоточный неблочный сервер сокетов Unix C), должен получить файл от клиента и передать его всем остальным клиентам, подключенным к серверу.

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

Я пытаюсь все это взломать, поставив "END" в конце потока. Однако иногда, когда несколько файлов отправляются подряд, «END» является частью того же буфера recv, что и начало следующего файла. Или, что еще хуже, иногда я получаю буфер, заканчивающийся EN, и на следующем проходе приходит D.

Каков наилучший подход, чтобы избежать ситуаций, упомянутых выше, я действительно не хочу, чтобы каждый раз, когда я получаю несколько байтов из цикла сокета, весь накопленный буфер проверял, является ли «END» его частью, а затем обрезался соответствующим образом ... Я уверен, что есть лучшее решение этого права?

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 03 марта 2012

Если recv() возвращает -1, это ошибка , и вам необходимо проверить errno.Скорее всего, это был EAGAIN или EWOULDBLOCK, что означает, что в буфере приема сокета в данный момент нет данных.Поэтому вам нужно повторно выбрать ().

Когда recv() возвращает ноль , узел отключил сокет и передача завершена.

1 голос
/ 03 марта 2012

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

if ((n = read(..., filelen)) > 0) {
    filelen -= n;
} 
0 голосов
/ 03 марта 2012

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

{
  ssize_t sizeRead = 0;

  while (sizeRead = recv(...)) {
    if (0 > sizeRead) { /* recv() failed */
      if ((EGAGAIN == errno) ¦¦ (EWOULDBLOCK == errno)) { /* retry the recv() on those two kinds of error */
        usleep(1) /* optional */
        continue;
      }
      else
        break;
    }

    ... /* process the data read ... */
  }

  if (0 > sizeRead) {
    /* There had been an error during recv() */
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...