моя клиентская система C ++ обеспечивает очень медленный обмен файлами ... почему? - PullRequest
1 голос
/ 07 января 2010

Привет реализовали простой обмен файлами через соединение клиент / сервер в c ++. Работает нормально, за исключением одной проблемы, которая так чертовски медленно. Это мой код:

Для отправки файла:

int send_file(int fd)
{

char rec[10];
struct stat stat_buf;
fstat (fd, &stat_buf);  
int size=stat_buf.st_size;

while(size > 0)
{
    char buffer[1024];
    bzero(buffer,1024);
    bzero(rec,10);
    int n;
    if(size>=1024)
    {
        n=read(fd, buffer, 1024);

        // Send a chunk of data
        n=send(sockFile_, buffer, n, 0 );

        // Wait for an acknowledgement
        n = recv(sockFile_, rec, 10, 0 );
    }
    else // reamining file bytes
    {
        n=read(fd, buffer, size);
        buffer[size]='\0';
        send(sockFile_,buffer, n, 0 );
        n=recv(sockFile_, rec, 10, 0 ); // ack
    }

    size -= 1024;

}

// Send a completion string
int n = send(sockFile_, "COMP",strlen("COMP"), 0 );
char buf[10];
bzero(buf,10);
// Receive an acknowledgemnt
n = recv(sockFile_, buf, 10, 0 );

return(0);
}

А для получения файла:

int receive_file(int size, const char* saveName)
{

ofstream outFile(saveName,ios::out|ios::binary|ios::app);


while(size > 0)
{       
    // buffer for storing incoming data
    char buf[1024];
    bzero(buf,1024);
    if(size>=1024)
    {

        // receive chunk of data
        n=recv(sockFile_, buf, 1024, 0 );

        // write chunk of data to disk
        outFile.write(buf,n);

        // send acknowledgement
        n = send(sockFile_, "OK", strlen("OK"), 0 );

    }
    else
    {
        n=recv(sockFile_, buf, size, 0 );
        buf[size]='\0';
        outFile.write(buf,n);
        n = send(sockFile_, "OK", strlen("OK"), 0 );
    }   

    size -= 1024;

}

outFile.close();

// Receive 'COMP' and send acknowledgement
// ---------------------------------------
char buf[10];
bzero(buf,10);
n = recv(sockFile_, buf, 10, 0 );
n = send(sockFile_,  "OK", strlen("OK"), 0 );
std::cout<<"File received..."<<std::endl;

return(0);
}

Теперь вот мои первые мысли: возможно, буфер слишком мал. Поэтому я должен попытаться увеличить размер с не знаю, 1024 байта (1 КБ) до 65536 (64 КБ) блоков, возможно. Но это приводит к повреждению файла. Итак, возможно, код также замедляется из-за необходимости получать подтверждение после отправки каждого 1024-байтового блока данных, так почему бы не удалить их? К сожалению, это приводит к тому, что блоки поступают не в правильном порядке и, следовательно, к повреждению файла.

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

Есть идеи, как сделать процесс передачи файлов более эффективным (более быстрым)?

Спасибо, Бен.

Ответы [ 5 ]

12 голосов
/ 07 января 2010

Пропустить подтверждение буфера! Вы вставляете искусственную обратную передачу (сервер-> клиент + клиент-> сервер) для каждого отдельного пакета.

Это замедляет передачу.

Вам не нужно это подтверждение. Вы используете TCP, который дает вам надежный поток. Отправьте количество байтов, затем отправьте весь файл. Не read после send и т. Д.

РЕДАКТИРОВАТЬ : В качестве второго шага вы должны увеличить размер буфера. Для передачи через Интернет вы можете принять MTU 1500, поэтому в каждом IP-пакете будет место для полезной нагрузки в 1452 байта. Это должен быть ваш минимальный размер буфера. Увеличьте его и позвольте операционной системе разделять буферы на пакеты для вас. Для локальной сети у вас гораздо выше MTU.

6 голосов
/ 07 января 2010

Я предполагаю, что вы не синхронизированы, и некоторые из ваших чтений меньше 1024. Это происходит постоянно с сокетами. Оператор "size - = 1024" должен быть "size - = n".

Я предполагаю, что n иногда меньше 1024 от recv ().

5 голосов
/ 07 января 2010

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

1 голос
/ 07 января 2010

Читать эту тему:

Отправка и получение файла при программировании сокетов в Linux с C / C ++ (GCC / G ++)

О, и используйте команду sendfile POSIX, вот пример для начала: http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt

0 голосов
/ 07 января 2010

Пара вещей.

1) Вы перераспределяете буфер каждый раз, когда проходите цикл while:

while(size > 0)
{
    char buf[1024];

Вы можете вытащить его из цикла while с обеих сторон, и вы больше не будете сбрасывать в стек.

2) 1024 - это стандартный размер буфера, и я бы не стал намного превышать 2048, потому что тогда стеку TCP / IP более низкого уровня просто придется его все равно разбивать.

3) Если вам действительно нужна скорость, вместо ожидания подтверждения вы можете просто добавить номер пакета в каждый пакет и затем проверить их на принимающей стороне. Это делает ваш принимающий код немного более сложным, потому что он должен хранить неупорядоченные пакеты и упорядочивать их. Но тогда вам не нужно подтверждение.

4) Это мелочь, но что если файл, который вы отправляете, имеет размер, кратный 1024 ... Тогда вы не будете отправлять завершающий символ '/ 0'. Чтобы это исправить, вам просто нужно изменить время на:

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