Запись на сервер в сокет, но данные не доходят до клиента - PullRequest
1 голос
/ 30 ноября 2011

Я пишу простой сервер для своего класса сетей, и у меня возникают проблемы с правильной передачей данных клиенту (предоставлен проф).

После того, как я прошел все настройки и установил соединение, я начинаю читать фрагменты файла и записывать их в сокет, проверяя, совпадают ли возвращаемые функции чтения и записи. Я также сохраняю итоговое количество прочитанных / записанных байтов и сравниваю их с общим размером файла (через stat.st_size), и все они совпадают.

Независимо от того, сколько раз я запрашиваю один и тот же файл, журнал на стороне сервера всегда имеет правильные метрики. Клиент время от времени теряет конец файла. Разница между фактическим и ожидаемым размером почти никогда не бывает одинаковой от одного вызова к другому, и кажется, что он всегда является концом отсутствующего файла, без каких-либо частей с середины. Размер поступившего файла также кратен 512 (размер чанка).

Итак, кажется, что некоторые целые куски делают это, а затем остальные как-то теряются.

#define CHUNK_SIZE     512
/* other definitions */

int main()
{
   /* basic server setup: socket(), bind(), listen() ...  
      variable declarations and other setup  */

   while(1)
   {
      int cliSock = accept(srvSock, NULL, NULL);
      if(cliSock < 0)
         ; /* handle error */

      read(cliSock, filename, FILE_NAME_SIZE - 1);
      int reqFile = open(filename, O_RDONLY);
      if( reqFile == -1)
         ; /* handle error */

      struct stat fileStat;
      fstat(reqFile, &fileStat);
      int fileSize = fileStat.st_size;

      int bytesRead, totalBytesRead = 0;
      char chunk[CHUNK_SIZE];
      while((bytesRead = read(reqFile, chunk, CHUNK_SIZE)) > 0)
      {
         totalBytesRead += byteasRead;
         if(write(cliSock, chunk, bytesRead) != bytesRead)
         {
            /* perror(...) */
            /* print an error to the log file */
            bytesRead = -1;
            break;
         }
      }
      if (bytesRead == -1)
      {
         /* perror(...) */
         /* print an error to the log file */
         close(cliSock);
         continue;
      }

      /* more code to write transfer metrics etc to the log file */
   }
}

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


Редактировать перевернул <, который должен был быть >

1 Ответ

2 голосов
/ 30 ноября 2011

Предположительно, вы бесцеремонно закрываете сокет с помощью close(), когда записываете все данные, которые хотите, в сокет (или, возможно, просто выходите из процесса, который делает то же самое).

Это неправильно - если другая сторона отправила данные, которые вы не прочитали 1 , соединение будет сброшено. Сброс может привести к потере непрочитанных данных.

Вместо этого вы должны использовать shutdown(), чтобы корректно отключить записывающую сторону сокета, а затем дождаться закрытия клиента. Что-то вроде:

ssize_t bytesRead;
char chunk[CHUNK_SIZE];

shutdown(cliSock, SHUT_WR);

while((bytesRead = read(cliSock, chunk, CHUNK_SIZE)) != 0)
{
    if (bytesRead < 0)
    {
        if (errno != EINTR)
        {
            /* perror() */
            /* print error in log file */
            break;
        }
    }
    else
    {
        /* maybe log data from client */
    }
}

close(cliSock);


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