Невозможно получить последние данные сокета, отправленные с использованием флага MSG_MORE - PullRequest
0 голосов
/ 29 апреля 2011

код на стороне сервера:

 dirp=opendir(path);
    if(dirp==NULL)
    {
        strcpy(err,"error:");
        strcat(err,strerror(errno));
        send(fd,err,sizeof(err),0); 
    }       
    else
    {
        printf("\nstream opened\n");
        while((dp=readdir(dirp))!= NULL)
        {

            r=send(fd,dp->d_name,100,MSG_MORE);
            if(r<0)
                perror("\nsend:");
            printf("\n%s",dp->d_name);

        }
    }

клиент:

while(recv(mainsocket,lsbuf,100,0)>0)
{
    printf("\n %s",lsbuf);
    bzero(lsbuf,sizeof(lsbuf)); 
}

на стороне сервера печатаются все имена файлов на стандартном выводе, но на стороне клиента клиент не получает последнее имя файла, и в этот момент программа блокируется

Ответы [ 2 ]

3 голосов
/ 29 апреля 2011

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

dp = readdir(dirp);
if (dp != NULL)
{
    /* each time check whether there are more data */
    while((dp_next = readdir(dirp))!= NULL)
    {
        r = send(fd, dp->d_name, 100, MSG_MORE);
        if (r < 0) {
            perror("\nsend");
        }
        printf("\n%s",dp->d_name);
        dp = dp_next;
    }

    /* send the last or the only record */
    r = send(fd, dp->d_name, 100, 0);
    if (r < 0) {
        perror("\nsend");
    }
}

Другая возможность исправить проблему - закрыть соединение с системным вызовом close(fd).Передача всех данных в буфер перед закрытием соединения.Это менее чистое, но более простое решение.

1 голос
/ 29 апреля 2011

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

Четыре решения:

  • используйте printf("%s\n", lsbuf); вместо ..."\n %s"...
  • используйте puts(lsbuf);, что имеет тот же эффект, но немного более уместно
  • используйте fflush(stdout) после цикла клиента, чтобы очистить буфер вывода
  • использовать небуферизованный вывод, подробности смотрите в setvbuf ()

Обратите внимание, что эта проблема не связана с сетью (хотя я бы заменилMSG_MORE с 0), это просто проблема с буферизацией вывода.

В отношении идентификатора я настоятельно рекомендую отправлять strlen(dp->d_name) + 1 байтов вместо 100 байтов.Таким образом, вы не будете отправлять больше байтов, чем необходимо, а с другой стороны, вы не будете усекать выходные данные, если ваши записи каталога окажутся больше 100 байтов.

Кроме того, ни ваш клиент, ни вашсервер проверяет, возвращает ли send() / recv() 0, что означает, что соединение было закрыто удаленным концом.

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