Не отправка файла правильно.Розетки.С - PullRequest
0 голосов
/ 25 апреля 2018

Я пишу программу, которую клиент может запросить файлы на сервере.Затем сервер отправит их кусками по 512 байт.Проблема в том, что когда клиент читает файл:

* Иногда первые 512 байт отличаются от исходного файла.Общий прочитанный файл также имеет другой размер (и, очевидно, он также отличается от исходного файла), и поэтому цикл клиента, который записывает в новый файл, никогда не заканчивается.

* Иногда он работает отлично, и я нене знаю почему.

Сервер:

            /* Check if file exists */
            if(access(retrFileName, F_OK) == 0){

                /* Open file */
                fd = open(retrFileName, O_RDONLY); 
                lseek(fd, 0, SEEK_SET);
                if (fd == -1){
                        fprintf(stderr, "Error opening file --> %s", strerror(errno));

                        exit(EXIT_FAILURE);
                }

                /* Get file stats */
                if (fstat(fd, &fileStat) < 0){
                        fprintf(stderr, "Error fstat --> %s", strerror(errno));
                        exit(EXIT_FAILURE);
                }

                sprintf(fileSize, "%li", fileStat.st_size);

                /* Sending file data */
                offset = 0;
                remainData = fileStat.st_size;
                while (((sentBytes = sendfile(clientSock, fd, &offset, 512)) == 512) && (remainData > 0)) {
                        remainData -= sentBytes;
                        fprintf(stdout, "Server envio %d bytes del file, offset ahora vale: %li y quedan = %d bytes\n", sentBytes, offset, remainData);
                }
                remainData -= sentBytes;
                fprintf(stdout, "Server envio %d bytes del file, offset ahora vale: %li y quedan = %d bytes\n", sentBytes, offset, remainData);//do while
                close(fd);////////////////////////
                send(clientSock, NICETRANSFER, sizeof(NICETRANSFER), 0); //LO METE AL ARCHIVO
                printf("send\n");
                //close(clientSock);///////////

            }
            else{
                send(clientSock, FILEERROR, sizeof(FILEERROR), 0);
                printf("send\n");
            }


        }

Клиент:

/* Open file */
            receivedFile = fopen("r.txt", "wb");
            if (receivedFile == NULL){
                fprintf(stderr, "Failed to open file --> %s\n", strerror(errno));

                exit(EXIT_FAILURE);
            }

            /* Write to the file */
            int contador = 0;
            int remainData = fileSize;
            do{
                if(remainData < 512)
                    bytesLeidos = recv(clientSock, readingBuffer, remainData, 0);
                else
                    bytesLeidos = recv(clientSock, readingBuffer, 512, 0);

                fwrite(readingBuffer, bytesLeidos, 1, receivedFile);

                remainData -= 512;
                contador += 512;
                printf("bytesleidos: %li, contador: %d:\n%s\n\n", bytesLeidos, contador, readingBuffer);

            }while(contador < fileSize);
            fclose(receivedFile);

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Я решил свою проблему !! Мне нужно было синхронизировать как клиента, так и сервера. Для этого сервер отправляет размер файла и ждет ответа для клиента с recv. Когда клиент получает размер файла, он send "" сообщение.

Я не знаю, является ли это правильным решением, но таким образом вы можете синхронизировать сервер и клиент.

После синхронизации сервер отправляет соответствующий файл обычно с sendfile

0 голосов
/ 25 апреля 2018

Золотое правило программирования сокетов: всегда проверяйте возвращаемое значение с recv. Это не всегда то, что вы думаете.

Даже если вы «отправляете» 512 байт за раз, вы никоим образом не гарантируете, что TCP будет доставлять получателю одинаковое количество байт за раз. Сегментация TCP, фрагментация IP и общая странность Интернета приведут к тому, что сторона recv получит произвольное количество байтов за раз.

Следовательно, ваше жестко заданное предположение, что recv всегда будет возвращать 512, неверно:

remainData -= 512;
contador += 512;

Вместо этого вы должны сказать:

remainData -= bytesLeidos;
contador += bytesLeidos;

Вам также необходимо проверить ошибки и закрытие сокетов.

Это улучшенный основной цикл для вашего клиентского кода:

while (remainData > 0)
{
    size_t recvSize = (remainData >= 512) ? 512 : remainData;
    bytesLeidos = recv(clientSock, readingBuffer, recvSize, 0);
    if (bytesLeidos > 0)
    {
        fwrite(readingBuffer, bytesLeidos, 1, receivedFile);
        remainData -= bytesLeidos;
        contador += bytesLeidos;

        /* null terminate readingBuffer so garbage isn't printed.*/
        /* Make sure readingBuffer is allocated to be at least */
        /*  N+1 bytes (513) to account for this character being appended. */

        readingBuffer[bytesLeidos] = '\0'; 
        printf("bytesleidos: %li, contador: %d:\n%s\n\n", bytesLeidos, contador, readingBuffer);
    }
    else if (bytesLeidos == 0)
    {
        /* remote side closed connection */
        printf("Remote side exited connection\n");
        break;   
    }
    else if (bytesLeidos < 0)
    {
         /* connection error */
        printf("Connection error\n");
        break;   
    }
}
...