LINUX.ORG.RU

многопоточное копирование фала через сокет

 , ,


0

1

Здравствуйте есть клиент сервер смысл в том что при подключении клиента к серверу(запускается отдельный поток) начинается копирование файла на сторону клиента вопрос в следующем возможно ли сделать так чтобы если запустить одновременно много клиентов(допустим 10-10 потоков ) файл копировался параллельно на все клиенты одновременно.

код сервера

#include <QCoreApplication>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <fcntl.h>
#include <pthread.h>
#include <QFile>
#include <QTime>
pthread_mutex_t s;
int i=0;
void* potokfunc(void* ps)  //начало потока функция
{
    int desk=*(int *)ps;
    char buf[100];  //отправка номера размера имени файла
    char buf2[2048]; //отправка данных файла
    pthread_mutex_lock(&s);
    i=i+1;
    pthread_mutex_unlock(&s);
 
 
    // ОТПРАВЛЯЕМ НОМЕР ПАПКИ
    sprintf(buf,"%d",i);
    printf("НОМЕР ПАПКИ=%s\n",buf);
    //sleep(1);
    int rez=send(desk,buf,strlen(buf),0);
    if (rez>0)
    {
        printf("номер папки отправлен \n");
    }
 
    memset(buf,0,sizeof(buf));  // очищаем буфер
 
    //ОТПРАВЛЯЕМ РАЗМЕР ФАЙЛА
    QFile a("/qqq");
    int razmer;
    razmer=rez=a.size();
    char *razmert=QString::number(rez).toLocal8Bit().data();
    //sleep(3);
    sprintf(buf,"%s",razmert);
    printf("РАЗМЕР ФАЙЛА=%s\n",buf);
    rez=send(desk,buf,strlen(buf),0);
    if (rez>0)
    {
        printf("размер файла отправлен\n");
 
    }
    memset(buf,0,sizeof(buf));  // очищаем буфер
    //ОТПРАВЛЯЕМ ИМЯ ФАЙЛА
    sprintf(buf,"%s","/qqq");
    printf("ИМЯ ФАЙЛА=%s\n",buf);
    //sleep(3);
    rez=send(desk,buf,strlen(buf),0);
    if (rez>0)
    {
        printf("имя файла отправлено \n");
 
    }
    //sleep(2);
    FILE *f=fopen(buf,"rb");
    if (f!=NULL)
    {
 
        while(!feof(f))
        {
            rez=fread(buf2,1,sizeof(buf2),f);
            if (rez>0)  // если данные в буфер передали
            {
                rez=send(desk,buf2,strlen(buf2),0);
                if (rez>0)
                {
                    razmer=razmer-rez;
                }
                if (razmer==0)  //весь файл считали
                {
 
                    break;
                }
            }
        }
    }
 
    return NULL;
 
 
 
}
 
int main(int argc, char *argv[])
{
    pthread_mutex_init(&s,0);
    int fd=socket(AF_INET,SOCK_STREAM,0);
    if (fd<0)
    {
        printf("ощибка создания сокета");
        return 0;
    }
    struct sockaddr_in sockad;
    struct sockaddr_in klient;
 
    sockad.sin_addr.s_addr=htonl(INADDR_ANY);
    sockad.sin_family=AF_INET;
    sockad.sin_port=htons(6643);
 
    int rez=bind(fd,(struct sockaddr *)&sockad,sizeof(sockad));
    if (rez<0)
    {
        printf("ошибка привязки");
        return 0;
    }
    rez=listen(fd,1000);
    if (rez<0)
    {
        printf("не готово принимать соединения\n");
        return 0;
    }
    printf("сервер запущен\n ЖДУ ПОДКЛЮЧЕНИЙ\n");
 
    while (1)
    {
        int len=sizeof(klient);
        int fda=accept(fd,(sockaddr *)&sockad,(socklen_t *) &len);
        if (fda>0)  //если произошло соединение
        {
            printf("произошло подключение создаю поток\n");
            pthread_t tid;  //создали объект потока
            int jj=pthread_create(&tid, NULL, &potokfunc, &fda);    //передаем связный файловый дескриптор
            if (jj!=0)
            {
                printf("поток не создан\n");
            }
            sched_yield();
        }
    }
 
 
 
 
    return 0;
}

код клиента

#include <QCoreApplication>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <fcntl.h>
#include <pthread.h>
#include <QFile>
#include <QTime>
#include <QDir>
#include <stdio.h>
 
using namespace std;
 
int main(int argc, char *argv[])
{
    char buf[100];
    char buf2[2048];
    memset(buf,0,sizeof(buf));
    memset(buf2,0,sizeof(buf2));
 
    int fd=socket(AF_INET,SOCK_STREAM,0);
    if (fd<0)
    {
        printf("ощибка создания сокета\n");
 
    }
 
    struct sockaddr_in sock;
    sock.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
    sock.sin_port=htons(6643);
    sock.sin_family=AF_INET;
 
    int rez=connect(fd,(sockaddr *)&sock,sizeof(sock));
    if (rez<0)
    {
        printf("ошибка коннекта\n");
        return 0;
    }
    //принимаем номер папки
    rez=recv(fd,buf,sizeof(buf),0);
    if (rez>0)
    {
        cout<<"НОМЕР ПАПКИ="<<buf<<endl;
        printf("номер папки получен\n");
    }
 
 
    QString papka="/1000ARM/"+QString(buf);
    cout<<papka.toStdString()<<endl;
    QDir a;
    a.mkdir("/1000ARM");
 
    if (a.mkdir(papka)==true)
    {
        printf("папка создана\n");
    }
 
    memset(buf,0,sizeof(buf));
    int razmer;
    //принимаем размер файла
    rez=recv(fd,buf,sizeof(buf),0);
    if (rez>0)
    {
        razmer=QString(buf).toInt();
        cout<<"РАЗМЕР ФАЙЛА="<<buf<<endl;
        printf("размер файла получен\n");
    }
 
    memset(buf,0,sizeof(buf));
 
    rez=recv(fd,buf,sizeof(buf),0);
    if (rez>0)
    {
        cout<<"ИМЯ ФАЙЛА="<<buf<<endl;
        printf("имя файла получено\n");
    }
 
    QString imyaf=papka+QString(buf);
    char *im=imyaf.toLocal8Bit().data();
    FILE *f=fopen(im,"wb");
    printf("\n");
    if (f!=NULL)
    {
        while(1)
        {
            memset(buf2,0,sizeof(buf2));
            rez=recv(fd,buf2,sizeof(buf2),0);
            if (rez>0)  //если мы получили данные
            {
                printf("данные получены=%s\n",buf2);
                rez=fwrite(buf2,1,rez,f); //данные записаны
                if (rez>0)  //если мы записали данные
                {
                     printf("получено байт=%d\n",rez);
                    razmer=razmer-rez;
                }
                if (razmer==0)
                {
                    printf("весь файл принят\n");
                    break;
                }
            }
        }
    }
 
 
 
 
    return 0;
}

Ответ на: комментарий от slackwarrior

у меня не будет 10 к соединений и при чем тут это? я спрашивал возможно ли читать(корректно читать) файл несколькими потоками

kold2015
() автор топика

..,,...,...,.,.,.,.,,.,..,.,..,.,..,,,.,.,.,,,,.,.,..,.,.,,.,.,.,.,.,,..,

Пользуйся.

ichi404
()

Если твое приложение работает не на встраиваемом железе (т.е. нет жестких ограничений по ресурсам) и потоков меньше 1000, может не думать об их количестве. Читать файл можешь во сколько угодно потоков.

P.S. Проблема C10k уже много лет как превратилась в C1M.

prefetch
()

int razmer;

Не переживай, у меня больше.

anonymous
()

Забульбень файл в shm, если буферам ведра не доверяешь! Но таки не вижу смысла: если клиентов дофига, то буферы сброситься не успеют и файл фактически постоянно будет в оперативке торчать.

// офтоп

#include <QCoreApplication>
#include <QFile>
#include <QTime>

..


    int fd=socket(AF_INET,SOCK_STREAM,0);
    if (fd<0)
    {
        printf("ощибка создания сокета\n");
 
    }

нострадамлю ощибку в ДНК. Хотя бы начиная с бреда вроде мешанины С и С++ и заканчивая идиотизмом вроде «ПАПКИ».

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

А общая траектория выплескивания жидкой дрисни в текстовый редактор тебе разве нравится? Мне нет. У меня аж сжалось все при виде такого форматирования (ну остальное анон и ты уже упомянули).

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

общая траектория напоминает «я тебя слепила из того, что было» ☺

Eddy_Em ☆☆☆☆☆
()

Я нифига не понял какой у тебя протокол используется. Смысл всех качальщиков в следующем:

  • используется модель поток:соединение 1:1
  • по возможности серверная часть использует вызов seek(), а в протоколе клиент и сервер знают как эту команду использовать
  • при особом извращении в одно соедениние протокол позволяет впихивать данные из разных файлов

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

Если клиенты на разных машинах и не имеют под собой системы с параллельными вычислениями, то смотри в сторону аудио-видео вещания. Если клиент запускается в многопоточном режиме, то без команды seek() ты далеко не уедешь; обходится хаком на стороне клиента, когда он пишет данные до момента Х в /dev/null.

gh0stwizard ★★★★★
()
Ответ на: комментарий от kold2015

Можно, но... не нужно :) А там есть классический ответ на твой вопрос. Алсо ман «мультиплексирование ввода-вывода» - заодно разберешься почему потоки тут не при чем :)

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)

printf(«НОМЕР ПАПКИ=%s\n»,buf);

ШТОЭТО? Зачем папку пронумировал?!

По делу. Если все правильно понял, то... 1. Можно взять ASIO и забить на потоки. 2. Для параллельного копирования можно сделать планировщик, ожидающий клиентов некоторое время и создающий, например, сессию, в пределах которой отсылать всем одни и те же данные.

Результат: код чище, масштабируемость, 1 чтение файла на N запрашивающих его клиентов.

anonymous
()
Ответ на: комментарий от gh0stwizard

используется модель поток:соединение 1:1

Есси чессно первый раз такой смысл качальщика вижу. 1:1 это сильно дофига и затратно. на 10 клиентов (или даже на 100) вполне хватит 1 потока и замапленного файла. Дело в протоколе, который у автора отсутствует.

anonymous
()
Ответ на: комментарий от anonymous

Фал — это ФАЛлический символ

anonymous
()

o_O на чем написано?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.