read(sock…) и write(sock…) не работают синхронно

209
13 апреля 2017, 19:20

C++, Ununtu 16.04 LTS, Компилятор g++

Всем доброго времени. Пишу клиент-серверное приложение. Задача довольно простая : передать файл от сервера клиенту. Отправляю клиенту размер файла, делю этот размер на 1024, чтобы получить количество пакетов, которое я должен получить (я отправляю по 1024 байта). С этой частью все в порядке. Когда начинается работа циклов for и while, то тут я сталкиваюсь с проблемой, что сервер быстренько обрабатывает все свои write, заталкивает весь файл в буфер и ждет. Клиент же читает почему-то только первые сколько-нибудь пакетов и потом останавливается на какой-то итерации. Далее - когда я в окне с сервером прерываю серверный процесс (ctrl+C на Ubuntu), то клиент сразу докачивает остальное до конца. Я не устанавливал неблокирующие сокеты. Не понимаю, в чем дело. Объясните, пожалуйста, если в курсе.

Клиент :

void Client::download(std::string filename)
{
    std::ofstream ofs(filename, std::ofstream::app);
    int nBytesReceived;
    int nFileLength = 0;
    int nPackages = 0;
    char buffer[1024];
    memset(buffer, '\0', sizeof(buffer));
    //Получение длины файла
    nBytesReceived = read(sockfd, buffer, sizeof(buffer));
    if (nBytesReceived < 0) 
        error("ERROR reading from socket");
    //Length of the file
    nFileLength = atoi(buffer);
    nPackages = nFileLength % BUF > 0 
    ? nFileLength / BUF + 1
    : nFileLength / BUF;
    //Тут происходит передача файла
    for(int i = 0; i<nPackages; ++i){
        //Read from the socket
        nBytesReceived = read(sockfd, buffer, sizeof(buffer));
        if (nBytesReceived < 0) 
            error("ERROR reading from socket");
        ofs<<buffer;
    }
    ofs.close();
}

Сервер :

void Server::upload(std::string filename, int nFilePos){
    std::ifstream ifs(filename, std::ifstream::in);
    char buffer[BUF];
    memset(buffer, 0, sizeof(buffer));
    ifs.seekg(0, ifs.end);
    int nFileLength = ifs.tellg();
    //Тут происходит отправка длины файла
    nBytesSent = write(newsockfd, std::to_string(nFileLength).c_str()
    , strlen(std::to_string(nFileLength).c_str()));
    if (nBytesSent < 0) 
        error("ERROR writing to pipe");    
    this->send();
    ifs.seekg(0, ifs.beg);
    //Тут происходит передача файла
    while (!ifs.eof()){
        ifs.read(buffer, BUF);
        nBytesSent = write(newsockfd, buffer, strlen(buffer));
        if (nBytesSent < 0) 
            error("ERROR writing to pipe");     
    }
    ifs.close();
}
Answer 1

Ваш сервер пишет пакеты длиной

strlen(buffer)

А клиент читает пакет длиной

sizeof(buffer)

Дальше два варианта:

  1. Ваш sockfd - это TCP. Если в буфере есть хоть один байт \0, то вся передача "разъезжается"...
  2. Ваш sockfd - это UDP - фактическую длину принятого блока надо самому проверять.
READ ALSO
Сравнение множества значений

Сравнение множества значений

Как коротко сравнить много значений на равенство? Надо такое поведение:

238
Двойная итерация в одном цикле

Двойная итерация в одном цикле

Как сделать так, чтобы одновременно в одном цикле шли две итерации (например i и j)?

241
Ошибка Broken file, keyframe not correctly marked

Ошибка Broken file, keyframe not correctly marked

При открытии файлаogv выдает в дампе ошибку "[ogg @ 00f0c400] Broken file, keyframe not correctly marked

257
Наибольшее слово в файле

Наибольшее слово в файле

Нужно сделать проверку на максимальное количество символов, чтобы найти наибольшее слово в файле

248