powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Работа с libevent
28 сообщений из 28, показаны все 2 страниц
Работа с libevent
    #38529201
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!

Используя метод bufferevent_read библиотеки libevent, столкнулся с проблемой принятия файла большого размера. При использовании обычных сокетов делал это в цикле, с помощью метода recv, при этом перед запуском цикла принимал размер файла, и для остановки цикла сравнивал этот размер с общим числом принятых байт, по частям записывая файл. Так как при реализации сервера через libevent чтение сообщения - это событие, получается что реализовать подобным способом здесь не получится - каждый новый прием данных заставляет метод приема выполнятся заново, и получается, что переданный файл записывается по частям в разные буферы, т.е. в один, но в конце приема в буфере остается только последние принятые байты файла.

Вопрос как реализовать прием файлов больших размеров используя libevent.

Спасибо!
...
Рейтинг: 0 / 0
Работа с libevent
    #38529339
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La France,

могу сказать только одно:очень странно, что именно ты пишешь этот самый высоко загруженный сервер, а не я.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529354
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZiv,

Почему странно?
...
Рейтинг: 0 / 0
Работа с libevent
    #38529585
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La Franceкаждый новый прием данных заставляет метод приема выполнятся заново, и
получается, что переданный файл записывается по частям в разные буферы, т.е. в один, но в
конце приема в буфере остается только последние принятые байты файла.
А писать в разные буферы, т.е. действительно в разные тебе мешает что?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Работа с libevent
    #38529601
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovLa Franceкаждый новый прием данных заставляет метод приема выполнятся заново, и
получается, что переданный файл записывается по частям в разные буферы, т.е. в один, но в
конце приема в буфере остается только последние принятые байты файла.
А писать в разные буферы, т.е. действительно в разные тебе мешает что?..


Как я потом соберу все в один буфер, так чтобы эти составные буферы не перепутались? Но как вариант попробую, с этим что-нибудь придумать. Спасибо.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529634
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceКак я потом соберу все в один буфер, так чтобы эти составные буферы не
перепутались?
Последовательно. Ты не поверишь, но порядок приёма не нарушается.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Работа с libevent
    #38529668
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не понял, откуда несколько буферов?
На каждое соединение - один буфер.
В этот буфер читаем из потока. Когда приходит событие чтения, записываем буфер в файл, и потом снова запускаем чтение в тот же буфер, пока не будет прочитано все что ожидается.
Потом через этот же буфер отправляем ответ в сокет.

Где у вас возникают несколько буферов?
...
Рейтинг: 0 / 0
Работа с libevent
    #38529669
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyВ этот буфер читаем из потока.
тут имел в виду "читаем из сокета"
...
Рейтинг: 0 / 0
Работа с libevent
    #38529677
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovПоследовательно. Ты не поверишь, но порядок приёма не нарушается.


Это понятно. А как быть с тем, что локальный буфер, который в методе чтения будет перезаписываться, каждый раз как возникнет новое событие чтения, а значит старые данные из этого буфера потеряются. Использовать в этом случае глобальную переменную для буфера, в который будет суммироваться все прочитанные байты нельзя, ведь у меня не один клиент и её(глобальную переменную) будут использовать все, следовательно в ней всегда будет черт знает что храниться. Это можно было бы решить написав структуру для новых подключений, где и хранился бы конечный буфер.

Но все это, как мне кажется, неправильно, ведь все должно прочитаться за одно выполнение метода чтения, а не быть разбросано по разным событиям.

Сейчас у меня вроде все байты читаются и ничего не теряется. Теперь нужно сделать так, чтобы это событие как-то блокировалось на время выполнения метода чтения, а по его завершению снова активировалось.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529687
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceА как быть с тем, что локальный буфер, который в методе чтения будет
перезаписываться, каждый раз как возникнет новое событие чтения, а значит старые данные из
этого буфера потеряются.
Обработать эти старые данные перед возвратом из обработчика. На худой конец - скопировать
в более другой буфер. Разве это не очевидно?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Работа с libevent
    #38529747
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyНе понял, откуда несколько буферов?
На каждое соединение - один буфер.

Все правильно. На каждое соединение буфер один.
Anatoly MoskovskyВ этот буфер читаем из сокета. Когда приходит событие чтения, записываем буфер в файл, и потом снова запускаем чтение в тот же буфер, пока не будет прочитано все что ожидается.
Потом через этот же буфер отправляем ответ в сокет.

Таким образом я реализовывал сервер на стандартных сокетах с использованием потоков, и у меня все замечательно работало. Но с использование libevent данные читаются/отсылаются не из/в сокет(-а), а из/в объект(-а) структуры bufferevent с помощью подобного recv методу bufferevent_read, который тоже возвращает число считанных байт. По сути, с использованием libevent не имеет значения откуда считывать данные - из сокета(есть возможность совместить стандартные сокеты и libevent для реализации сервера, но сказали делать только с помощью libevent) или объекта структуры bufferevent, так как в любом случае будет срабатывать событие чтения пока из сокета или объекта структуры bufferevent есть что читать. И получается, что не успеет метод полностью прочитать все присланные байты файла, как срабатывает событие чтения и часть данных считывается в другом вызове метода, в ТОТ же буфер, но так как он является локальным для метода, то он же является и другим по отношению к другому вызову метода.

Надеюсь в последнем предложении я ответил на ваш вопрос относительно того где возникают несколько буферов.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529764
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La France,
Не, про буфера так и не понял.
Ну да ладно. Это не принципиально.

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

Таким образом, чтобы все работало вам надо к моменту выхода из обработчика чтения закончить обработку данных в буфере.
А пока вы не выйдете из обработчика никто ваш буфер не тронет.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529771
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovОбработать эти старые данные перед возвратом из обработчика. На худой конец - скопировать
в более другой буфер. Разве это не очевидно?..

Это очевидно. Свои мысли по этому поводу я высказал в том же сообщении.
La FranceИспользовать в этом случае глобальную переменную для буфера, в который будет суммироваться все прочитанные байты нельзя, ведь у меня не один клиент и её(глобальную переменную) будут использовать все, следовательно в ней всегда будет черт знает что храниться. Это можно было бы решить написав структуру для новых подключений, где и хранился бы конечный буфер.

Но все это, как мне кажется, неправильно, ведь все должно прочитаться за одно выполнение метода чтения, а не быть разбросано по разным событиям.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529797
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceDimitry SibiryakovОбработать эти старые данные перед возвратом из обработчика. На худой конец - скопировать
в более другой буфер. Разве это не очевидно?..

Это очевидно. Свои мысли по этому поводу я высказал в том же сообщении.
La FranceИспользовать в этом случае глобальную переменную для буфера, в который будет суммироваться все прочитанные байты нельзя, ведь у меня не один клиент и её(глобальную переменную) будут использовать все, следовательно в ней всегда будет черт знает что храниться. Это можно было бы решить написав структуру для новых подключений, где и хранился бы конечный буфер.

Но все это, как мне кажется, неправильно, ведь все должно прочитаться за одно выполнение метода чтения, а не быть разбросано по разным событиям.



MasterZiv,

Почему странно?


Вот ПО ЭТОМУ и странно...
...
Рейтинг: 0 / 0
Работа с libevent
    #38529807
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyНо суть в том, что не может прийти следующее событие, пока находимся внутри обработчика.

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

Не совсем согласен. Без конца щелкая по кнопке на форме все события будут обработаны, естественно, если обработчик не будет блокировать форму. Допустим в обработчике будет запущен бесконечный цикл, тогда форма зависнет, но если по каждому нажатию на кнопку циклы будут запускаться в новых потоках, то все они будут выполняться не блокируя форму. Думаю в libevent события работают подобным образом, поэтому срабатыванию нового события не мешает незаконченность обработки предыдущего.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529823
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZivВот ПО ЭТОМУ и странно...


Подобное объяснение мне не понятно. С намёками и сарказмом у меня проблемы. Поэтому, могу лишь сделать предположение к чему вы клоните. В любом случае, что мешает вам заняться написанием такого сервера, какой вас устроит?
...
Рейтинг: 0 / 0
Работа с libevent
    #38529870
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceMasterZivВот ПО ЭТОМУ и странно...


Подобное объяснение мне не понятно. С намёками и сарказмом у меня проблемы. Поэтому, могу лишь сделать предположение к чему вы клоните. В любом случае, что мешает вам заняться написанием такого сервера, какой вас устроит?

Я всё понимаю. Всё правильно. Лучше и не знать...

А мешает -- отсутсвие времени и денег.
...
Рейтинг: 0 / 0
Работа с libevent
    #38529871
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La France,

Ты бы ужо КОД опубликовал бы, мож быстрее и помогли б.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530161
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceБез конца щелкая по кнопке на форме все события будут обработаны, естественно, если обработчик не будет блокировать форму. Допустим в обработчике будет запущен бесконечный цикл, тогда форма зависнет, но если по каждому нажатию на кнопку циклы будут запускаться в новых потоках, то все они будут выполняться не блокируя форму. Думаю в libevent события работают подобным образом, поэтому срабатыванию нового события не мешает незаконченность обработки предыдущего.
Да не работает libevent подобным образом. Там внутри одного цикла событий ровно один поток, и пока выполняется обработчик ничего больше не может в принципе выполняться.

Грубо говоря внутри происходит следующее:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
//event loop
while (1)
{
  event = wait_for_events();
  switch (event) {
  case read:
      socket.read(buffer) // читает сколько пришло на данный момент
      read_handler()
      break;
  case write: ....    
  }
}


Как вы видите событие приходит не после чтения в буфер, а перед ним. Т.е. неважно какие там события пришли пока ваш обработчик выполнялся, libevent с буфером работает только полсе того как обработчик завершится.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530326
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZivА мешает -- отсутсвие времени и денег.

Написание этого сервера является частью моей работы, поэтому вопроса о времени и деньгах у меня не стоит.
MasterZivТы бы ужо КОД опубликовал бы, мож быстрее и помогли б.

Переделываю эхо-сервер для своих задач.

В методе echo_read_cb первый вариант был следующий:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
    memset(tmp, 0, sizeof(tmp));
    n = bufferevent_read(buf_ev, tmp, sizeof(tmp));//принимаем размер файла
    int size = atoi(tmp);
    cout<<"size: "<<size<<endl;
    
    ofstream outf("/home/qwe/Desktop/file2.txt", ifstream::binary);
    int allBytes = 0;
    n = 0;
    do
    {
        memset(tmp, 0, sizeof(tmp));
        n = bufferevent_read(buf_ev, tmp, sizeof(tmp));
        allBytes += n;
        //cout<<"tmp: "<<tmp<<endl;
        //cout<<"n: "<<n<<endl;
        //cout<<"allBytes: "<<allBytes<<endl;
        outf.write(tmp, n);//записываем очередные байты в файл
    }
    while(allBytes != size);//читаем пока количество принятых байт не равно размеру файла
    
    //if (n < 0)
        //error("Ошибка чтения из сокета");
    
    outf.close();


С использованием сокетов и потоков - это рабочий вариант, но только не здесь. Так как разные части файла читаются в разных вызовах этого метода, то число байт никогда не будет равно размеру файла, и уже при втором вызове метода size будет равен 0, так как это число будет преобразовываться из части байт файла.

Сейчас вариант такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
  char tmp[1024];
  size_t n;
  int allBytes = 0;
  
  while(1)
  {
      memset(tmp, 0, sizeof(tmp));
      n = bufferevent_read(buf_ev, tmp, sizeof(tmp));
      allBytes += n;
      if (n <= 0)//если все прочитали, выходим из цикла
          break;
      
      //cout<<"tmp: "<<tmp<<endl;//очередная порция байт файла
      cout<<"n: "<<n<<endl;количество принятых байт за одно прочтение
  }
  
  cout<<"allBytes: "<<allBytes<<endl;//все байты после выполнения цикла


Тут считываются все байты файла, но за несколько событий. Сейчас нужно как-то блокировать событие чтения на время выполнения метода, чтобы все байты файла читались за одно выполнение метода, а потом снова разблокировать это событие.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530328
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyКак вы видите событие приходит не после чтения в буфер, а перед ним. Т.е. неважно какие там события пришли пока ваш обработчик выполнялся, libevent с буфером работает только полсе того как обработчик завершится.

Тем не менее факт остается фактом:
Вывод
-------------------------------------Событие: 1
n: 1024
n: 1024
n: 872
allBytes: 2920
-------------------------------------Событие: 2
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 3
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 4
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 5
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 6
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 7
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 8
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 9
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 10
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 11
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 12
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 13
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 14
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 15
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 16
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 17
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 18
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 19
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 20
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 21
n: 1024
n: 1024
n: 1024
n: 1024
allBytes: 4096
-------------------------------------Событие: 22
n: 152
allBytes: 152

Здесь сервер принимает файл размером 84992, если посчитать все принятые байты - сложить все allBytes то получится 84992, то есть весь файл пришел, но прочитался за 22 события. Как-то так.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530332
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сейчас выяснилось, что в цикле где происходит чтение, через несколько операций чтения - вызова метода bufferevent_read(как видно из вывода выше в основном через пять операций чтения, на пятый уже ничего не читает), метод возвращает 0, а следовательно он прекращает работу цикла (дает возможность сработать событию снова), но потом срабатывает новое событие и чтение продолжается. Вопрос: почему так происходит?

Anatoly Moskovsky, теперь с вами согласен.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530443
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La France
Код: plaintext
1.
while(allBytes != size);//читаем пока количество принятых байт не равно размеру файла


откуда уверенность, что сервер отдаст все ожидаемые байты?
...
Рейтинг: 0 / 0
Работа с libevent
    #38530456
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
[/src][/quot]
откуда уверенность, что сервер отдаст все ожидаемые байты?
[/quot]
Если вы о том, что в случае, когда не все данные придут от клиента, то цикл никогда не завершится, то отвечу, что в реализации с сокетами у меня это обрабатывается и работает нормально.
...
Рейтинг: 0 / 0
Работа с libevent
    #38530582
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceТут считываются все байты файла, но за несколько событий. Сейчас нужно как-то блокировать событие чтения на время выполнения метода, чтобы все байты файла читались за одно выполнение метода, а потом снова разблокировать это событие.
У вас в корне неверное понимание как асинхронная обработка происходит.

Вы не можете в обработчике собятия чтения в цикле читать пока не прочтете нужное кол. байтов.

Вместо этого вы должны при нехватке данных запрашивать новое чтение и выходить из обработчика чтения.
А чтобы при приходе новых данных обработчик продолжил с того же места, вы должны хранить состояние обработки в неком объекте и каким-то образом передавать его в каждый обработчик.

Как в libevent поддерживать состояние сеанса я уже не помню, давно ничего не нем не делал. Поэтому порекомендовал Boost.Asio где из предыдущего обработчика в следующий можно передавать произвольный набор аргументов. Не говоря уже про то, что там вообще все на порядки проще чем в libevent (К примеру, сервер , чья сетевая часть была написана мной на libevent за месяц, я переписал на Boost.Asio за один день)

Но раз вам начальство приказало libevent использовать, то ищите более сложные примеры чем Echo в котором состояние не требуется поддерживать.
...
Рейтинг: 0 / 0
Работа с libevent
    #38531358
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyУ вас в корне неверное понимание как асинхронная обработка происходит.

Ну, вроде как есть представление. Я ведь описываю фактическую работу программы, а не то, как она должна в теории работать. Работа в теории и на практике обычно всегда отличается.

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

За одно событие никак не получается считать байты, даже если не блокировать цикл, метод считает максимум 4096 байт, а дальше всегда будет 0 выдавать.
...
Рейтинг: 0 / 0
Работа с libevent
    #38531798
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
La FranceЯ сейчас написал класс для подключенного клиента, и сохраняю, принятые за несколько срабатываний события чтения, байты в один буфер. Только теперь необходимо как-то узнавать, что все данные пришли и готовы к обработке. Приходят все байты, по размеру проверял.
Ну, вы в правильном направлении движетесь - разбирайтесь дальше.
...
Рейтинг: 0 / 0
Работа с libevent
    #38532666
La France
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovsky,

Сделал наконец. Отправляю файл с клиента на сервер и записываю его из буфера в файл. Две эти операции выполняются за 12 минут 5 секунд при размере файла 1,26 ГБ. Для проверки, весь ли файл пришел, сначала посылаю размер файла, потом сравниваю его размер с тем, что принял. Сервер сейчас на виртуальной машине находится. Нужно теперь структуру писать и её передавать.
...
Рейтинг: 0 / 0
28 сообщений из 28, показаны все 2 страниц
Форумы / C++ [игнор отключен] [закрыт для гостей] / Работа с libevent
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]