Я получаю некоторые значения мусора при отправке данных файла через сокет на сервер?Зачем? - PullRequest
0 голосов
/ 01 февраля 2019

Я устанавливаю соединение клиент-сервер через сокеты в C ++.Я успешно соединяю их, но при отправке файлов и данных о файлах я получаю некоторые значения мусора и на моем сервере.

Сначала я отправляю Размер файла через системный вызов send от клиента, а затем отправляю Buffer файла на сервер.

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

Код клиента

File = fopen("index.jpg", "rb");
if (!File)
{
    MessageBox(L"Error while readaing the file");

}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);

char* Buffer = new char[Size];

fread(Buffer, Size, 1, File);



char cSize[MAX_PATH];
sprintf(cSize, "%lu", Size);



send(Socket, cSize, MAX_PATH, 0); // File size
send(Socket, Buffer, Size, 0); // File Binary

Код сервера

          unsigned long Size;
    char *Filesize = new char[1024];

    if (recv(Sub, Filesize, 1024, 0)) // File size
    {
       Size = strtoul(Filesize, NULL, 0);  //getting filesize
    }


    Buffer = new char[Size];
    int reader = recv(Sub, Buffer, Size, 0);
    Buffer[Size] = '\0';
    if (reader == -1) // File Binary
    {
        MessageBox(L"Perror Recv");
    }
    else if (reader == 0)
    {
        MessageBox(L"Connection is Closed");
    }
    else
    {
        FILE *File;
        File = fopen("test.jpg", "wb");
        fwrite((const char*)Buffer, 1, Size, File);  
        MessageBox(L"DATA Received");
        fclose(File);
    }

1 Ответ

0 голосов
/ 01 февраля 2019

Одна проблема в том, что вы неправильно обрабатываете возвращаемые значения из recv().Например:

if (recv(Sub, Filesize, 1024, 0)) // File size

... когда функция, указанная выше, возвращает значение, она записывает некоторое количество байтов (больше 0, меньше 1025) в Filesize.Как много?Ваша программа не знает, потому что вы не сохранили возвращаемое значение в переменной, чтобы выяснить это (скорее вы только проверили его, чтобы увидеть, было ли оно ненулевым, или нет, а затем сбросили значение).Следовательно, вполне вероятно, что Filesize содержит не только значение размера вашего файла, но и некоторую часть данных вашего файла ... именно поэтому эта часть данных вашего файла не будет записана на диск позже в вашемprogram.

Подобная проблема здесь:

int reader = recv(Sub, Buffer, Size, 0);

Вы проверяете reader, чтобы увидеть, является ли это -1 или 0 (что хорошо), но в вашем финалеЕсли вы просто fwrite() из Size байтов из массива, когда Buffer содержит reader байтов, а не Size байтов (и reader может иметь любое значение от 1 до Size, в зависимости отсколько байтов стек TCP решил доставить вам в этом конкретном recv() вызове.

Еще одна проблема заключается в том, что вы отправляете MAX_PATH байтов для размера файла, но вы получаете (до) 1024 байтадля размера файла. MAX_PATH равно 1024? Если нет, то даже если recv() заполнило все 1024 байта, ваш отправитель и получатель все равно будут не синхронизированы друг с другом, так как избыточные байты будут отображаться вбудущие recv() звонки или (альтернативно) вы получите байты от последующих вызовов send(), помещенных в ваш буфер FileSize.

Так что это прямая проблема - я думаю, что основная проблема заключается в том, что вы делаете некоторые предположения о том, как работает сеть TCP, которыене правда.В частности:

  • Нет гарантии однозначного соответствия между send() и recv() вызовами.(TCP является протоколом потока байтов и не создает данных)

  • Вы не можете полагаться на N байтов данных от одного вызова до send(), доставляемого черезодин звонок на recv().Байты, которые вы send(), будут доставлены по порядку, но нет никаких гарантий относительно того, сколько вызовов на recv() потребуется для их получения, а также на то, сколько байтов любой данный вызов recv() записывает в ваш прием.-buffer.

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

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

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