Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> удаленный вызов. детали, реализация, архитектура, у темы новое название! 
:(
    Опции темы
boostcoder
  Дата 6.10.2010, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



всем доброго дня.
имеем тип T:
Код

template<typename T>
struct any_type {
   enum { id = unique_id };
   typedef ... get_type;
   typedef ... set_type;
};

в runtime мы получаем id`ы.
хочу реализовать что-то вроде типозависимого прокси callable`ра(хз как правильно назвать).

сигнатура методов/объектов такая:
Код

void method(T::set_type& set, const T::get_type& get);


нужна возможность регистрировать методы/объекты имея в runtime только id, и ин compile_time T::id.
т.е. зная T::id ат compile_time и id в runtime, назначать методы/объекты принимающие соответствующие им типы.

пример конечного использования:
Код

// any types
struct type1 { id = ... };
struct type2 { id = ... };
struct type3 { id = ... };
...
struct proxy { // registrator
   template<typename T>
   void reg(method_with_needed_signature_ptr);
};
// methods impl
...
void method1(type1::set_type& set, const type1::get_type& get) {}

void method2(type2::set_type& set, const type2::get_type& get) {}

void method3(type3::set_type& set, const type3::get_type& get) {}
...
// reg in proxy
proxy.reg<type1>(method1);
proxy.reg<type2>(method2);
proxy.reg<type3>(method3);

...
// call proxy
int id = ...
type1 arg = ...
proxy(id)(arg.set_type, arg.get_type);


как-то так...
запутался, и ничего в голову не лезет...

Это сообщение отредактировал(а) boostcoder - 3.4.2011, 01:58
PM WWW   Вверх
xvr
Дата 6.10.2010, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(boostcoder @  6.10.2010,  11:23 Найти цитируемый пост)
нужна возможность регистрировать методы/объекты имея в runtime только id, и ин compile_time T::id.

IMHO сие невозможно. Либо id должен быть известен в compile time, либо реализация proxy вообще не должна зависеть от id

Либо я не понял требования задачи - что с чем и по каким признакам надо связать? Во что должен развернуться
Код

proxy(id)(arg.set_type, arg.get_type);
?


PM MAIL   Вверх
mes
Дата 6.10.2010, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  6.10.2010,  10:23 Найти цитируемый пост)
зная T::id ат compile_time и id в runtime

это разные числа , или одно и то же ? 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 6.10.2010, 17:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(xvr @  6.10.2010,  11:32 Найти цитируемый пост)
Во что должен развернуться

если id == type1::id, то должен произойти вызов method1(...)


Цитата(mes @  6.10.2010,  11:46 Найти цитируемый пост)
это разные числа , или одно и то же ?

int id имеет диапазон type1::id ... typeN::id

два уточнения:
1. typeN::id - это enum. так что можно использовать в mpl.
2. у всех typeN общий предок.


Это сообщение отредактировал(а) boostcoder - 6.10.2010, 17:21
PM WWW   Вверх
mes
Дата 7.10.2010, 01:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



было б лучше если б дали немного сведений и о задачи, а именно какие требования предъявляются к рантайм..

вот на полусне : http://liveworkspace.org/code/c8cf16a805aa...0bc837af0545038
в том хоть направлении ?

Добавлено через 3 минуты и 27 секунд
это Вы удаленный вызов реализуете ?

Добавлено через 5 минут и 19 секунд
Цитата(boostcoder @  6.10.2010,  16:19 Найти цитируемый пост)
2. у всех typeN общий предок.

Цитата(boostcoder @  6.10.2010,  10:23 Найти цитируемый пост)
(type1::set_type& set, const type1::get_type& get) 

а что ж тогда не объект класса typeN передается  ?





--------------------
PM MAIL WWW   Вверх
maxim1000
Дата 7.10.2010, 08:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 17
Всего: 110



Цитата(boostcoder @  6.10.2010,  11:23 Найти цитируемый пост)
proxy(id)(arg.set_type, arg.get_type);

в параметрах должны быть типы или значения соответствующих типов?



--------------------
qqq
PM WWW   Вверх
boostcoder
Дата 7.10.2010, 08:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  7.10.2010,  01:02 Найти цитируемый пост)
это Вы удаленный вызов реализуете ?

да.

Цитата(mes @  7.10.2010,  01:02 Найти цитируемый пост)
в том хоть направлении ?

похоже на то. покурю...

Цитата(mes @  7.10.2010,  01:02 Найти цитируемый пост)
а что ж тогда не объект класса typeN передается  ?

можно и тип. но задача не упростится. я для пользователя удобней и понятней.

Цитата(maxim1000 @  7.10.2010,  08:44 Найти цитируемый пост)
в параметрах должны быть типы или значения соответствующих типов?

значения.
PM WWW   Вверх
mes
Дата 7.10.2010, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  7.10.2010,  07:50 Найти цитируемый пост)
можно и тип. но задача не упростится. я для пользователя удобней и понятней.

при использовании структуры кол-во аргументов функции постоянно.


--------------------
PM MAIL WWW   Вверх
mes
Дата 7.10.2010, 15:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

template <class T> 
void register_handler ( void (*fn)(const T&) )
{
     arr[T::id] = (fn_t)fn;    
}
 

register_handler (&f1);



подправленная версия :  http://liveworkspace.org/code/3b42cd08948e...84cf01e63c3374e



--------------------
PM MAIL WWW   Вверх
maxim1000
Дата 8.10.2010, 00:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 17
Всего: 110



можно упаковывать полученные аргументы в boost::any
а методы оборачивать во что-то шаблонное, унаследованное от общего интерфейса (который и принимает эти boost::any)

Добавлено через 55 секунд
(правда, не получится пользоваться неявными преобразованиями)


--------------------
qqq
PM WWW   Вверх
mes
Дата 8.10.2010, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



в примере обработчиками выступают функции, но у конечному пользователь захочется иметь что либо более универсальное..поможет класс Dispatchera, для конвертации параметра и класс функции (напр boost::function)
http://liveworkspace.org/code/09b6daf1e59d...aee0c15a1aff76d

на "ляпы"  не относящиеся к сути проблемы (такие как неподходящий способ хранения) внимания не обращать smile



--------------------
PM MAIL WWW   Вверх
mes
Дата 8.10.2010, 22:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



кстати вспомнил, goldfinch  одно время на форуме разбирал темы связанные с удаленными вызовами..
не помню к чему он там конкретно пришел, но думаю Вам будет тематически полезно ознакомиться с этим материалом.. 
если найдете прикрепите ссылки к теме, плиз
smile


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 03:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  8.10.2010,  22:23 Найти цитируемый пост)
кстати вспомнил, goldfinch

я даже аккаунта такого не могу найти. и функцию поиска аккаунтов тоже :(

пока курю ваш пример. хочется автоматизировать это все.
написать кодогенератор на препроцессоре - не проблема. но есть несколько неудобных моментов. думаю...

Это сообщение отредактировал(а) boostcoder - 9.10.2010, 03:12
PM WWW   Вверх
boostcoder
Дата 9.10.2010, 07:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, сделал так, как вы предложили:
Код

/***************************************************************************/

struct i_dispatcher {
   virtual ~i_dispatcher() {}
   virtual void dispatch(constants::header_packet&, constants::body_packet&) = 0;
};

/***************************************************************************/

template<typename C, typename T>
struct methods_dispatcher: i_dispatcher {
   typedef void(C::*handler_t)(typename T::result_type&, const typename T::query_type&);
   /**  */
   methods_dispatcher(C& p, handler_t h):_this(p),_handler(h) {}

   virtual void dispatch(constants::header_packet& h, constants::body_packet& b) {
      typename T::query_type query = deserializer(h, b);
      typename T::result_type result;
      (_this.*_handler)(result, query);
      serializer(h, b, result);
   }

private:
   C& _this;
   handler_t _handler;
};

/***************************************************************************/

template<typename C>
struct proxy_caller {
   proxy_caller(C* p, constants::header_packet& h, constants::body_packet& b)
      :_parent(p),_header(h),_body(b)
   {}

   template<typename T>
   void register_handler(typename methods_dispatcher<C, T>::handler_t handler) {
      if ( _map.find(T::id) != _map.end() ) {
         throw std::runtime_error("id(" +  boost::lexical_cast<std::string>((int)T::id) + ") already registered");
      }
      _map[T::id] = dispatcher_ptr(new methods_dispatcher<C, T>(*_parent, handler));
   }

   void call() {
      constants::header hdr = constants::decode_header(_header);
      _map[hdr.id]->dispatch(_header, _body);
   }

private:
   C* _parent;
   constants::header_packet& _header;
   constants::body_packet& _body;
   typedef boost::shared_ptr<i_dispatcher> dispatcher_ptr;
   std::map<int, dispatcher_ptr> _map;
};

/***************************************************************************/


используется это дело так:
Код

struct implementation {
   implementation():_proxy(this, ....) {
      _proxy.register_handler<type1>(&implementation::method1);
      _proxy.register_handler<type2>(&implementation::method2);
   }

   void method1(type1::result_type& r, const type1::query_type& q) {
   }
   void method2(type2::result_type& r, const type2::query_type& q) {
   }

   proxy_caller<implementation> _proxy;
};


метод proxy_caller::call() вызывается из сетевой части после того, как буфера на которые ссылается proxy_caller заполнены.
как видно из реализации метода methods_dispatcher::dispatch(), ответ отправляется обратно при выходе из тела этого метода.
не худшая реализация RPC из тех что я видел smile 
но хочется большего.
а именно: скрыть от юзера все, кроме самого implementation.

в идеале, цель хочу видеть такой:
Код

// декларация интерфейса некоторого типа.
INTERFACE_BEGIN(transaction_type)
   METHOD(
      std::string, // ret
      login, // method name
      std::string, // method arg
      std::string // method arg
   )
   METHOD(
      std::string, // ret
      get_balance, // method name
      std::string, // method arg
      std::string // method arg
   )
INTERFACE_END()

// код клиента
client<transaction_type> client(host, port);
std::string ret = client.login("nick", "pass");
ret = client.get_balance("date from", "date to");

но тут есть непонятка...
т.к. клиент, всего лишь дергает методы сервера, ему их реализация не нужна. но она нужна серверу.
вот и непонятка: что на самом деле нужно на стороне клиента, чтоб дергать методы сервера? и что нужно знать серверу, чтоб понять, какой именно метод вызывает клиент?
PM WWW   Вверх
mes
Дата 9.10.2010, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  02:12 Найти цитируемый пост)
я даже аккаунта такого не могу найти. 

ну проще было искать тему, и поставить ограничение по юзеру..
вобщем вот об этой я говорил :
http://forum.vingrad.ru/forum/topic-269086...tml#st_0_view_0


Это сообщение отредактировал(а) mes - 9.10.2010, 10:53


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 10:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



почитал.
но в теме не нашел ничего полезного касательно реализации. а готовое не устраивает по ряду причин, обсуждать которые нет желания.
PM WWW   Вверх
mes
Дата 9.10.2010, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  09:52 Найти цитируемый пост)
но в теме не нашел ничего полезного касательно реализации.

да, я тоже прочитал, по старой памяти думал там больше полезного smile

Добавлено @ 11:03
вот например метод login... напишите отдельно, как Вы представляете, клиентскую и серверную часть функционала не затрагивая реализацию rpc, т.е. фактически конечные точки Вашей схемы.

Это сообщение отредактировал(а) mes - 9.10.2010, 11:05


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, а что именно описать? как это все происходит сейчас? или что?...
метод login - просто метод. вызывая его на стороне клиента, его аргументы отправляются на сервер, десериализуются, вызывается назначенный для этого типа запроса обработчик, тот в свою очередь получает дополнительный аргумент по ссылке в который кладет ответ, ответ сериализуется, отправляется клиенту, клиент десериализует его, и возвращает юзеру объект типа ответа.

PM WWW   Вверх
mes
Дата 9.10.2010, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  10:23 Найти цитируемый пост)
 а что именно описать? как это все происходит сейчас? или что?...

имелся ввиду код взаимодействия.. как Вы его видите..
например так :
Код

// client 
void login  () {
   login_t::result res << connection << login_t::query("name", "pass");

}
// server
void on_login (login_t::query cont & q )
{
     if (q.name==  ... && q.pass ==..  )
      connection << login_t::result (eOK);
  else ...
}


Добавлено @ 11:37
Цитата(boostcoder @  9.10.2010,  10:23 Найти цитируемый пост)
, его аргументы отправляются на сервер, десериализуются, вызывается назначенный для этого типа запроса обработчик, тот в свою очередь получает дополнительный аргумент по ссылке в который кладет ответ, ответ сериализуется, отправляется клиенту, клиент десериализует его, и возвращает юзеру объект типа ответа.

это как раз лишнее, так как  
Цитата(mes @  9.10.2010,  09:54 Найти цитируемый пост)
 не затрагивая реализацию rpc,



Это сообщение отредактировал(а) mes - 9.10.2010, 11:45


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 11:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



понял.
вот нынешний реальный код на стороне клиента. он даже работает smile 
Код

      client client(argv[1], std::atoi(argv[2]));
      /**  */
      connectToServer::value_type ret = client.query<connectToServer>(std::string("John"));
      std::cout << ret->msg() << std::endl;
      getUserList::value_type ret1 = client.query<getUserList>(11);
      std::cout << ret1->users()[0] << std::endl;


client::query<>() возвращает смарт-поинтер.

Добавлено через 2 минуты и 25 секунд
Цитата(mes @  9.10.2010,  11:34 Найти цитируемый пост)
// client 
void login  () {
   login_t::result res << connection << login_t::query("name", "pass");
}
// server
void on_login (login_t::query cont & q )
{
     if (q.name==  ... && q.pass ==..  )
      connection << login_t::result (eOK);
  else ...
}

что-то у меня это по удобнее получилось smile

Добавлено через 4 минуты и 21 секунду
на стороне сервера, каждый тип команды, ассоциирован с методом обработчиком.
PM WWW   Вверх
mes
Дата 9.10.2010, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



первое что бросается в глаза, value_type не очень удачное название.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, почему? как тогда его лучше назвать?
мне многие названия в моем коде не нравятся, наверное фантазии не хватает)
PM WWW   Вверх
mes
Дата 9.10.2010, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



второе, что у Вас не ассинхронный обмен - так и нужно ?



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  11:51 Найти цитируемый пост)
не ассинхронный обмен

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

Это сообщение отредактировал(а) boostcoder - 9.10.2010, 11:54
PM WWW   Вверх
mes
Дата 9.10.2010, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  10:51 Найти цитируемый пост)
как тогда его лучше назвать?

как не знаю.. просто  за value_type уже закрепилось некоторое смысловое значение, которое не совпадает с приведенным применением.. 
ну например response_type или return_type ..

Добавлено через 2 минуты и 36 секунд
Цитата(boostcoder @  9.10.2010,  10:53 Найти цитируемый пост)
пока не вызывается один из методов value_type.

не до конца понял..
запрос к серверу идет здесь
Цитата(boostcoder @  9.10.2010,  10:44 Найти цитируемый пост)
  connectToServer::value_type ret = client.query<connectToServer>(std::string("John"));

или здесь 
Цитата(boostcoder @  9.10.2010,  10:44 Найти цитируемый пост)
    std::cout << ret->msg() << std::endl;

?


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  11:55 Найти цитируемый пост)
или return_type

да, так лучше.

PM WWW   Вверх
mes
Дата 9.10.2010, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  10:53 Найти цитируемый пост)
 иначе, вызывающий поток приостанавливается

т.е. ассинхронность введена специально ? или все ж так получилось ?

Добавлено через 4 минуты и 43 секунды
Цитата(boostcoder @  9.10.2010,  10:44 Найти цитируемый пост)
что-то у меня это по удобнее получилось 

ну так не удивительно.. я то написал спонтанно smile


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



здесь:
Цитата

connectToServer::value_type ret = client.query<connectToServer>(std::string("John"));

он ставится в очередь на основе boost::thread + asio::io_service + boost::packaged_task<>

но при вызове любого из методов результата, вызывается boost::unique_future::get(), который приостанавливает вызывающий цикл.

Добавлено @ 12:08
Цитата(mes @  9.10.2010,  11:59 Найти цитируемый пост)
т.е. ассинхронность введена специально ?

да, специально.

Добавлено @ 12:14
хотя в этом есть некоторое не очевидное поведение: если вдруг asio::io_service::run выполнить в нескольких потоках(типа пул потоков), и сделать один запрос к серверу ничего не возвращающий но сохраняющий в объект сессии некоторое значение, и следом за ним сделать запрос получающий это значение, то может получится так, что второй запрос придет на сервер раньше smile 
чтоб исключить такую ситуацию, в тип нужно добавить служебный метод, что-то типа wait(). сделаю... позже..

Добавлено @ 12:19
Код

client client(...);
client.query<put_t>(33); // т.к. нам не интересно, уже доставилось значение, или нет
get_t::return_type res1 = client.query<get_t>(); // тут мы можем попытаться получить его в то время как оно еще в_очереди/в_пути


Это сообщение отредактировал(а) boostcoder - 9.10.2010, 12:20
PM WWW   Вверх
boostcoder
Дата 9.10.2010, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



собственно сейчас меня интересует, каким образом можно авторегистрировать методы-обработчики на стороне сервера, учитывая такую структуру:
Код

#include <iostream>
#include <boost/shared_ptr.hpp>

struct implementation {
   void method() {}
};

template<typename C>
struct proxy {
   proxy(C* p):_parent(*p) {}

   template<typename T>
   void register_handler(void (C::*handler)()) {
   }
   
   C& _parent;
};

template<typename IF>
struct connection {
   connection():_impl(new IF),_proxy(_impl.get()) {
      _proxy.template register_handler<int>(&IF::method);
   }
   boost::shared_ptr<IF> _impl;
   proxy<IF> _proxy;
};

int main() {
   connection<implementation> context;
}


http://liveworkspace.org/?id=bb4bddf94368b...b96872fa347ec98
connection - объект сессии с клиентом.

Это сообщение отредактировал(а) boostcoder - 9.10.2010, 21:13
PM WWW   Вверх
mes
Дата 9.10.2010, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



интуитивно напрашивается такой псевдо-код :
Код

   rpc<login_t> 
     login(client, login_t::query("John"));

   login.wait(100);

   std::cout << login.result;

где rpc это шаблонная структура обертка, отвечающая за отправку запроса клиенту, ожидание и предоставления доступа к результату.

Добавлено через 3 минуты и 6 секунд
Цитата(boostcoder @  9.10.2010,  11:41 Найти цитируемый пост)
, каким образом можно авторегистрировать методы-обработчики на стороне сервера, 

не приглядывался но мне кажется вы хотите, чтоб у сервера на все пакеты были перегруженные функции с одним именем..
тогда вам поможет список_типов..  

Это сообщение отредактировал(а) mes - 9.10.2010, 12:41


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



для этого, нужен метагенератор, генерирующий метаинформацию из к примеру, такого макроса:
Код

INTERFACE_BEGIN(transaction_type)
   METHOD(
      std::string, // ret
      login, // method name
      std::string, // method arg
      std::string // method arg
   )
   METHOD(
      std::string, // ret
      get_balance, // method name
      std::string, // method arg
      std::string // method arg
   )
INTERFACE_END()

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

т.е. для этого интерфейса должна быть такая реализация:
Код

struct transaction_type {
   std::string login(std::string, std::string) {}
   std::string get_balance(std::string, std::string) {}
};


есть идеи?

Добавлено через 4 минуты и 44 секунды
Цитата(mes @  9.10.2010,  12:41 Найти цитируемый пост)
интуитивно напрашивается такой псевдо-код

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

Цитата(mes @  9.10.2010,  12:41 Найти цитируемый пост)
вы хотите, чтоб у сервера на все пакеты были перегруженные функции с одним именем..

нет. на каждый тип команды свой метод обработчик на сервере.

PM WWW   Вверх
mes
Дата 9.10.2010, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  11:46 Найти цитируемый пост)
есть идеи? 

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

сообщение про список типов видели ? если приведете функции обработчики к одному имени, то выгадаете (не кодогенеруеммую, а шаблонную) автоматизацию
smile
Цитата(boostcoder @  9.10.2010,  11:46 Найти цитируемый пост)
 на каждый тип команды свой метод обработчик на сервере.

естественно разный, но с таким же именем ))



Это сообщение отредактировал(а) mes - 9.10.2010, 12:56


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 12:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  12:52 Найти цитируемый пост)
как из макроса генерить описание серверного обработчика ? 

 smile нет.

я не очень представляю, что именно макрос должен сгенерировать, чтоб без реализации на стороне клиента слинковать программу, а на стороне сервера понять что к чему и как вязать.

Добавлено через 2 минуты и 48 секунд
Цитата(mes @  9.10.2010,  12:41 Найти цитируемый пост)
тогда вам поможет список_типов..

что имеется в виду?

Добавлено через 5 минут и 26 секунд
Цитата(mes @  9.10.2010,  12:52 Найти цитируемый пост)
естественно разный, но с таким же именем

имена у них тоже разные:
Код

struct implementation {
   implementation() {}

   void connectToServer_handler(connectToServer::result_type& r, const connectToServer::query_type& q);
   void getUserList_handler(getUserList::result_type& r, const getUserList::query_type& q);
};



Это сообщение отредактировал(а) boostcoder - 9.10.2010, 12:55
PM WWW   Вверх
mes
Дата 9.10.2010, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  11:54 Найти цитируемый пост)
что имеется в виду?

у буста что то в этом роде : 

Код

boost::mpl::for_each (register, boost::mpl::list<type1, type2, type3>);


ну а сервер выглядит так
Код

struct server {
  void handle (type1 &);
  void handle (type2 &);
  void handle (type3 &);

};



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



т.е. вы предлагаете решение, в котором для идентификации методов используется список типов аргументов? я правильно Вас понял?

Цитата(mes @  9.10.2010,  13:13 Найти цитируемый пост)
struct server {
  void handle (type1 &);
  void handle (type2 &);
  void handle (type3 &);
};

неудобно тем, что имена одинаковые.
разобрать аргументы метода на список типов, и собрать их обратно - не проблема. проблема именно в имени метода.
PM WWW   Вверх
mes
Дата 9.10.2010, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  12:19 Найти цитируемый пост)
неудобно тем, что имена одинаковые.
разобрать аргументы метода на список типов, и собрать их обратно - не проблема. проблема именно в имени метода.

фактически именем метода будет выступать имя типа пакета..
а чем неудобно одинаковое имя ?

Добавлено через 51 секунду
Цитата(boostcoder @  9.10.2010,  12:19 Найти цитируемый пост)
 в котором для идентификации методов используется список типов аргументов?

да список типов будет определять какие обработчики предоставляет сервер.

Добавлено через 1 минуту и 58 секунд
Цитата(boostcoder @  9.10.2010,  12:19 Найти цитируемый пост)
разобрать аргументы метода на список типов, и собрать их обратно - не проблема. 

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

Добавлено через 2 минуты и 50 секунд
не обязательно напрямую, возможно через прослойку, только внешне не видную.

Добавлено через 4 минуты и 56 секунд
сейчас еще одна идея пришла... надо обдумать.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  13:25 Найти цитируемый пост)
типы должны задаваться интерфейсом, который вы кодогенерируете..

имел в виду их и разобрать.

пока не представляю, что должно генерироваться на стороне клиента, чтоб прога скомпилилась..
на стороне сервера - понятно, из сгенерированного кода берется информация необходимая для связывания указателя на объект реализации интерфейса с которым должна связываться.
PM WWW   Вверх
mes
Дата 9.10.2010, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  13:11 Найти цитируемый пост)
пока не представляю, что должно генерироваться на стороне клиента, чтоб прога скомпилилась..

клиент заканчивается отправкой сериализированного объекта в _сокет_.

Добавлено через 1 минуту и 30 секунд
хотя да.. я забыл что еще ответ надо ждать.. вот тут есть проблемка... 


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  14:33 Найти цитируемый пост)
хотя да.. я забыл что еще ответ надо ждать.. вот тут есть проблемка...

угу.
но вроде как можно приблизительно так(мысли в слух):
на стороне клиента, сгенериный интерфейс используется совместно с классом client<interface>
на стороне сервера, сгенериный интерфейс используется совместно с классом server<interface>
то что генерится, должно содержать в себе какое-то значение времени компиляции которое client<> и server<> будут читать, то можно реализовать их таким образом, чтоб каждый брал для себя только то, что ему нужно. 

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

серверу, нужна полная реализация, методы которой, вызываются из оберток.

как-то так...
PM WWW   Вверх
boostcoder
Дата 9.10.2010, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(boostcoder @  9.10.2010,  14:45 Найти цитируемый пост)
можно реализовать их таким образом, чтоб каждый брал для себя только то, что ему нужно.


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

// описание интерфейса из которого будет сгенерирован метакод.
INTERFACE_BEGIN(type1)
   METHOD(int, add, int, int);
   METHOD(int, sub, int, int);
INTERFACE_END()

// вызов процедуры так:
client<type1> client(...);
int result = client.add(2,1); // это было бы идеальным вариантом

// на стороне сервера, реализация должна выглядеть так:
struct type1 {
   int add(int a, int b) {
      return a+b;
   }
   int sub(int a, int b) {
      return a-b;
   }
};
// но, т.к. реализацию пишем мы сами, сервер в первую очередь должен уметь связывать 
// информацию полученную о вызываемом методе от клиента.
server<type1> server(...); // сервер только знает о том, с каким типом ему предстоит работать.
// при входящем подключении, сервер, создает динамический объект type1, связывает запросы от клиента с реальным объектом.


и возвращаемся к старому вопросу:
1. что должен генерировать метагенератор на стороне клиента?
2. что должен генерировать метагенератор на стороне сервера?
3. как связать сгенерированную информацию с реальным, написанным нами, классом?
PM WWW   Вверх
mes
Дата 9.10.2010, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

2. запрос сохраняется и выделяется уникальный нумер операции 
  т.е. тогда возможны два запроса подряд одного типа. 

3. каждый вид запроса может существовать только в единственном экземпляре.. 
 но тут опять видна несогласованность, ответ может придти на  предыдущий запрос, который мы отменили..

Добавлено через 4 минуты и 45 секунд
насчет сервера... у нас есть некий компонент, который локально выполняет некую работу..
мы должны определить связку между запросом и компонентом..
т.е. на каждый тип запроса у нас должен быть бинд забирающий инфу откомпонента.. 
по идеи значит надо для диспетчера создать таблицу лямб функций возвращаюших ответ, на запрос..

Добавлено через 5 минут и 18 секунд
ну так и получается, что имя функции нам не нужно.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  15:20 Найти цитируемый пост)
1. либо у нас строгая очередность, и нет следующего запроса пока не получет ответ. имхо, не имеет смысла

так и запланировано.
выше, я просто привел пример, каким образом можно получить неочередность. а так как запросы живут в одном io_service, то все они выполняются строго в том порядке, в каком были добавлены в очередь.
PM WWW   Вверх
mes
Дата 9.10.2010, 15:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  14:26 Найти цитируемый пост)
а так как запросы живут в одном io_service, то все они выполняются строго в том порядке, в каком были добавлены в очередь. 

т.е. в сеть не отправляется ничего, до тех пора пока не получен ответ ? имхо не рационально .. 



--------------------
PM MAIL WWW   Вверх
mes
Дата 9.10.2010, 17:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 20:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @ 9.10.2010,  15:30)
Цитата(boostcoder @  9.10.2010,  14:26 Найти цитируемый пост)
а так как запросы живут в одном io_service, то все они выполняются строго в том порядке, в каком были добавлены в очередь. 

т.е. в сеть не отправляется ничего, до тех пора пока не получен ответ ? имхо не рационально ..

да.
я понимаю, что можно запросам присваивать ID`ы. но это пока не главный вопрос.

Добавлено через 3 минуты и 18 секунд
Цитата(mes @  9.10.2010,  17:38 Найти цитируемый пост)
кстати при подобной архитектуре сервер получается пассивным, т.е. сообщает только ту информацию которую запросил клиент..

да.

Цитата(mes @  9.10.2010,  17:38 Найти цитируемый пост)
очень часто бывает необходимость, о сообщение клиенту деталей без его запроса..

можно реализовать следующим образом: в client<> добавить deadline_timer, который сам будет слать серверу запросы, и при получении ответов, вызывать некоторый обработчик.

но и это не главное.

Цитата(boostcoder @  9.10.2010,  15:07 Найти цитируемый пост)
1. что должен генерировать метагенератор на стороне клиента?
2. что должен генерировать метагенератор на стороне сервера?
3. как связать сгенерированную информацию с реальным, написанным нами, классом? 


PM WWW   Вверх
mes
Дата 9.10.2010, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  9.10.2010,  19:25 Найти цитируемый пост)
1. что должен генерировать метагенератор на стороне клиента?
2. что должен генерировать метагенератор на стороне сервера?
3. как связать сгенерированную информацию с реальным, написанным нами, классом? 


имхо вопрос не с той стороны задан.. 
для начала нужно представить модель, а как потом это все запихнуть в кодогенерацию дело техники 
smile

Добавлено через 39 секунд
т.е. для начала надо представить как будет выглядить код..

Добавлено через 1 минуту и 17 секунд
итак Вы решили (с чем я не согласен) что синхронность будет удобнее..

Добавлено через 2 минуты и 12 секунд
тогда у нас есть rpc::client, к которому мы можем посылать запросы и получать ответ

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

Добавлено через 4 минуты и 44 секунды
тогда при отправке запроса, мы должны получить некую структуру контроллера-наблюдателя..

Добавлено через 8 минут и 32 секунды
допустим это будет выглядить так :

Код

rpc::track<rpc::login> login = client.send ( rpc.login::query("John"));
login.set_timeout (30);
while ( login.in_process() ) do_something ();
if ( ! login().is_ok() )  return;


Добавлено через 9 минут и 45 секунд
отвлекемся на сервер .. 



--------------------
PM MAIL WWW   Вверх
mes
Дата 9.10.2010, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



сервер хранит модель и список клиентов (сокетов) которые хотят ее изменить.. 
объект сервера выступает своего рода контроллером этих взаимодействий
тогда 
Код

struct server {

   list <client *> clients;
   model_t  model;
 
   void handle (client& , rpc::login);
   void handle (client& .. ); 
  
};


Добавлено @ 21:16
теперь нам необходимо как то зарегистрировать функции 
можно сделать массив/карту делегатов и связать их,

Добавлено @ 21:21
а можно отделить внутренности сервера от методов обработчиков .. 
тогда вместо методов обработчиков определяем таблицу вызовов
и тогда регистриуемая функция будет иметь вид
Код

template<class T>
void () (client&, server_context& , T& packet ) ;


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

Это сообщение отредактировал(а) mes - 9.10.2010, 21:23


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 9.10.2010, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  9.10.2010,  20:58 Найти цитируемый пост)
итак Вы решили (с чем я не согласен) что синхронность будет удобнее..

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

пишу мысли... минутку..
PM WWW   Вверх
mes
Дата 9.10.2010, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



итого значит сервер представлен у нас списком клиентом, контекстом/моделью/сессию (что нагляднее) и таблицей "виртуальных " функций.. 

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

Добавлено @ 21:30
итого значит у нас есть rpc::server и rpc::client (не пустать с rpc::server::client ) осуществляющие связь посредством сырых данных и взаимодействующие с пользователем типизированным пакетами.

Добавлено @ 21:36
т.е общий код выглядит так 
Код

// server
rpc::server<model_t> server;
server.register_handler ([](rpc::server<>::client& , model_t&, rpc::login&) // это можно задефайнить
              {       } )

// client
rpc::track<rpc::login> login = client.send ( rpc.login::query("John"));


Добавлено через 9 минут и 58 секунд
писал rpc::login но по сути пакеты должны находится в другом неймспейсе, например название протокола..

Добавлено через 11 минут и 7 секунд
все.. вроде свои мысли высказал..


Это сообщение отредактировал(а) mes - 9.10.2010, 21:36


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 10.10.2010, 01:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



вот как я вижу модель:
в данный момент, для каждого входящего соединения(т.к. клиенты сначала подключаются к серверу), создается объект, указанный в типе шаблона сервера. таким образом, получается так, что каждый клиент общается со своим собственным объектом. при завершении сеанса, объект удаляется.
есть еще вариант, инициализировать объект сервер, ссылающимся на общий для всех клиентов объект. в таком случае, так как объект реализует кодер, то синхроннизация/разделение_доступа ложится на него.
Код

type1 t1;
server<type1> server(...);
server.bind(t1);


тогда, в дополнение, было бы мегаудобным, реализовать в классе client<> запрос, типа create_session<type>(). который будет на стороне сервера создавать объект сессии, и переключать контекст клиента на этот объект.
если пойти немного дальше, то класс server<> можно реализовать так, чтоб список шаблонных аргументов был переменным. в таком случае, клиент, может делать запросы на создание какого-то конкретного объекта сессии, и пользоваться им.
Код

server<type1, type2, type3, type4> server(...);

...
...

client client(...);
client::session_ptr<type1> t1ptr = client.create_session<type1>();
// далее, вызываем методы предоставляемые типом type1
...

client::session_ptr<type2> t2ptr = client.create_session<type2>();
// далее, вызываем методы предоставляемые типом type2
...


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

Это сообщение отредактировал(а) boostcoder - 10.10.2010, 01:58
PM WWW   Вверх
mes
Дата 10.10.2010, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  10.10.2010,  00:54 Найти цитируемый пост)
в данный момент, для каждого входящего соединения(т.к. клиенты сначала подключаются к серверу), создается объект, указанный в типе шаблона сервера. таким образом, получается так, что каждый клиент общается со своим собственным объектом. при завершении сеанса, объект удаляется.

но насколько я понял, у вас к примеру  есть комнаты, в которые могут зайти разные клиенты, а значит сессия (или ее контекст) не у каждого своя а разделяемая(shared).

Цитата(boostcoder @  10.10.2010,  00:54 Найти цитируемый пост)
если пойти немного дальше, то класс server<> можно реализовать так,

детали реализации действительно лишние.. как удобнее сделать, будет видно при кодировании.. главное разобраться с сутью взаимоотношений.



Цитата(boostcoder @  10.10.2010,  00:54 Найти цитируемый пост)
сейчас первостепенный вопрос в том, какие данные должен генерировать кодогенератор чтоб клиент и сервер могли автосвязывать запросы/ответы с методами/реализацией?

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

Добавлено @ 09:39
список типов определяет какими сообщениями они могут обмениваться, а также для для сервера служит основой для таблицы регистрации..

Добавлено @ 09:44
как выглядит пакет и какие данные он должен содержать зависит от клиента и сервера.. поэтому имхо первостепенный вопрос стоит не в кодогенераторе, а в проектирование конечных точек соединения.. при том для упрoщения можно реализовывать в одной проге и  передавать данные напрямую, как в начале темы через  функции типа  void call(id, void*);

Это сообщение отредактировал(а) mes - 10.10.2010, 09:44


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 11.10.2010, 02:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  10.10.2010,  09:37 Найти цитируемый пост)
но насколько я понял, у вас к примеру  есть комнаты, в которые могут зайти разные клиенты, а значит сессия (или ее контекст) не у каждого своя а разделяемая(shared).

сессия - контекст пользователя/соединения.
комнаты - некоторые объекты, взаимодействие с которыми происходит посредством сессий.

Цитата(mes @  10.10.2010,  09:37 Найти цитируемый пост)
на мой взгляд достаточно только генерации пакетов, и списка типов пакетов. 
клиент и сервер должны быть целыми (не кодогенерируемыми) шаблонами.

наверное я вас не понимаю.. поясните пожалуйста.

немного пораздумав.. должно получиться как-то так:
Код

// декларация интерфейса.
INTERFACE_BEGIN(type1)
   METHOD(int, add, int, int);
   METHOD(int, sub, int, int);
INTERFACE_END()

// нужно сгенерировать что-то вроде этого:
// этот код используется только на стороне клиента.
struct type1 {
   int add(int a, int b) {
      static const int function_id = 0; // вставляет кодогенератор
      // пакуем данные..
      serialize(function_id, a, b); // вставляет кодогенератор
      // посылаем, десериализуем, возвращаем результат
      return send(serialized_buffer);
   }
   int sub(int a, int b) {
      static const int function_id = 1; // вставляет кодогенератор
      // пакуем данные
      serialize(function_id, a, b); // вставляет кодогенератор
      // посылаем, десериализуем, возвращаем результат
      return send(serialized_buffer);
   }
private:
   type1(protocol_implementation& pi):pi(pi) {}

private:
   protocol_implementation& pi;
};

// класс клиента:
template<typename IF>
struct client: IF {
   client(host, port):IF(pi),pi(host, port) {}

private:
   protocol_implementation pi;
};

// ну и на клиентской стороне использовать так:
client<type1> client(...);
int res = client.add(2,3);
int res1 = client.sub(res,3);


сервер:
Код

// на стороне сервера, юзер пишет реализацию:
struct type1 {
   int add(int a, int b) {
      return a+b;
   }
   int sub(int a, int b) {
      return a-b;
   }
};
// но, т.к. реализацию пишем мы сами, сервер должен уметь связывать локальный объект с 
// идентификаторами которые использует клиент для обозначения метода используемого для обработки посланного запроса.
// т.е. получается так, что метагенератор должен генерировать какой-то класс, присваивая ему имя типа binder_for_type1.
// но что из себя должен представлять класс binder_for_type1? и какую информацию содержать?



Это сообщение отредактировал(а) boostcoder - 11.10.2010, 02:39
PM WWW   Вверх
mes
Дата 11.10.2010, 10:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



ловите в упрощенном виде : http://liveworkspace.org/code/bbc75134b93c...914597f9c23e38b
с односторонним обменом клиент->сервер

rpc - библиотека конечных точек взаимодействия
ptcl -(кодогенерируемый) протокол обмена
my_server - оболочка реализующая поведение сервера (может быть определена как неймспейсом, так и классом)

ну и в глобальном пространстве условных запуск трех программ, сервера и двух клиентов.. 




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 11.10.2010, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, большое спасибо smile 
сейчас буду разбираться.

зы
на liveworkspace работает табуляция в коде. еще Ctrl+G, Ctrl+F, Ctrl+R, Ctrl+Z. оцените smile 

Это сообщение отредактировал(а) boostcoder - 11.10.2010, 10:53
PM WWW   Вверх
mes
Дата 11.10.2010, 10:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



 smile 
Цитата(boostcoder @  11.10.2010,  09:48 Найти цитируемый пост)
на liveworkspace работает табуляция в коде. еще Ctrl+G, Ctrl+F, Ctrl+R. оцените

даже не ожидал  ! учту, спасибо )



--------------------
PM MAIL WWW   Вверх
mes
Дата 11.10.2010, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



и я еще раз насчет (а)синхронности...  мне кажется вместо классического вызова функций с получением ответа, где сервер выступает в пассивной форме,
удобнее было бы воспользоваться системой взаимообмена сообщений, тогда клиент будет обладать такой же таблицей методов, как и сервер
а пакеты разделяться на две группы (client_to_server, server_to_client);




Это сообщение отредактировал(а) mes - 11.10.2010, 13:45


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 11.10.2010, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @ 11.10.2010,  11:10)
и я еще раз насчет (ас)синхронности...  мне кажется вместо классического вызова функций с получением ответа, где сервер выступает в пассивной форме,
удобнее было бы воспользоваться системой взаимообмена сообщений, тогда клиент будет обладать такой же таблицей методов, как и сервер
а пакеты разделяться на две группы (client_to_serever, server_to_client);

да. согласен. это хороший вариант.

PM WWW   Вверх
boostcoder
Дата 25.10.2010, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



продолжим-с...
что у меня есть сейчас:
Код

struct i_registration_api {
   virtual void user_exists_handler ( user_exists_result&, const user_exists_query& ) = 0;
   virtual void registration_handler ( registration_result&, const registration_query& ) = 0;
   virtual void activation_handler ( activation_result&, const activation_query& ) = 0;
   i_registration_api () {
      _map[0] = i_invoker_ptr( new invoker< i_registration_api, user_exists >(this, &i_registration_api::user_exists_handler ) );
      _map[1] = i_invoker_ptr( new invoker< i_registration_api, registration >(this, &i_registration_api::registration_handler ) );
      _map[2] = i_invoker_ptr( new invoker< i_registration_api, activation >(this, &i_registration_api::activation_handler ) );
   }
   // этот метод дергает сервер. наверное его нужно спрятать от юзера...
   virtual void proxy_call(constants::header_packet& h, constants::body_packet& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }
private:
   std::map<int, i_invoker_ptr> _map;
};


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

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

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


mes, вы в теме? smile 

Это сообщение отредактировал(а) boostcoder - 25.10.2010, 23:43
PM WWW   Вверх
mes
Дата 26.10.2010, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  25.10.2010,  22:41 Найти цитируемый пост)
недостаток в том, что пока что, сервер строго привязан типом шаблона.

не до конца понятно о чем тут.. 

над кодом сейчас подумаю.. но сразу чувствуется, что пока это не то что надо .. 


Это сообщение отредактировал(а) mes - 26.10.2010, 11:29


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 11:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  11:28 Найти цитируемый пост)
не до конца понятно о чем тут..

вот:
Код

struct registration_api: i_registration_api {
// реализуем виртуальные методы
};

server<registration_api> server(...); // все. сервер может работать только с этим типом.

но это плохая реализация. нелепо как-то, в один интерфейс пихать сотни методов smile 
PM WWW   Вверх
mes
Дата 26.10.2010, 11:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  10:33 Найти цитируемый пост)
но это плохая реализация. нелепо как-то, в один интерфейс пихать сотни методов 

понял.. Вы о том что у сервера только один исполнитель...  ага.. это не то.. но по этому поводу у мя вопрос : 
исполнители должны иметь каждый свою группу сообщений или некоторые сообщения будут для исполнителей общие ?





--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  11:38 Найти цитируемый пост)
исполнители должны иметь каждый свою группу сообщений или некоторые сообщения будут для исполнителей общие ?

у каждого свои сообщения + общие.
общие, это:
я хочу реализовать переброс исключений со стороны сервера клиенту. возможно еще какие-то технические данные.

еще момент. проблема с конструкторами исполнителей. каким образом реализовать поддержку аргументов для конструкторов?

Добавлено через 2 минуты и 15 секунд
сейчас приведу структуру классов для понимания..

Добавлено через 12 минут и 20 секунд
Код

template<typename IF>
struct user_context {
   user_context():_impl(new IF) {}
   boost::shared_ptr<IF> _impl;
   // все остальное скрыто.
};

template<typename IF>
struct server {
// по boost::asio::ip::tcp::acceptor::async_accept() создается новый user_context<IF>
};

где IF - тип исполнителя.
PM WWW   Вверх
mes
Дата 26.10.2010, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  10:51 Найти цитируемый пост)
я хочу реализовать переброс исключений со стороны сервера клиенту. возможно еще какие-то технические данные.

опять на помню, может уговорю пересмотреть контракт с сервером с запрос->ответ, на вызов<->вызов
smile


Цитата(boostcoder @  26.10.2010,  10:51 Найти цитируемый пост)
еще момент. проблема с конструкторами исполнителей. каким образом реализовать поддержку аргументов для конструкторов?

оставить создание исполнителя на стороне пользователя..

Добавлено через 42 секунды
как вариант передавать библиотеке ссылку на фабрику..

Добавлено через 3 минуты и 18 секунд
итак для начал нам нужно ограничить проблему.. 
что мы имеем ?
набор некоторых типов данных с ид
набор исполнителей

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




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  12:11 Найти цитируемый пост)
пересмотреть контракт с сервером с запрос->ответ, на вызов<->вызов

я пока что не представляю как это должно выглядеть/функционировать.. на самом деле, я понимаю, что то, каким образом сейчас происходит общение - это тупик. но не понимаю я как это должно функционировать smile 
поясните плиз ;)

Цитата(mes @  26.10.2010,  12:11 Найти цитируемый пост)
как вариант передавать библиотеке ссылку на фабрику.. 

да, вариант.. набросаю пример..
PM WWW   Вверх
mes
Дата 26.10.2010, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  11:18 Найти цитируемый пост)
да, вариант.. набросаю пример.. 

не торопитесь с этим ..

Добавлено через 12 секунд
Цитата(boostcoder @  26.10.2010,  11:18 Найти цитируемый пост)
поясните плиз ;)

сейчас



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



кстати. так же, было бы шикарно, реализовать возможность передавать серверу аргумент для исполнителя при запросе его создания.
Код

client client(...);
client::result_type<registration_api> reg = client.create<registration_api>(arguments...);

 smile 
PM WWW   Вверх
mes
Дата 26.10.2010, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  11:18 Найти цитируемый пост)
не представляю как это должно выглядеть/функционировать..

Ваша схема (если убрать все лишнее) выглядит так :
Код

struct  client;

struct server {
   login_result login (client&) { return .. }
   quit_result  quit (client&)  { return .. }    
};

class client {
   login_result login () { return m_server.login(*this); }
   quit_result quit ()   { return m_server.quit(*this); }  
   
   client(server&s) : m_server(s) {}
   
   server& m_server;
};

главный недостаток в том, что сервер предоставляет информацию ТОЛЬКО по запросу пользователя..
то есть например сообщения чата, будут читаться только когда пользователь запросит, а сервер должен их хранить все это время... 
а не тогда когда кто то написал.. 
 




--------------------
PM MAIL WWW   Вверх
xvr
Дата 26.10.2010, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mes @  26.10.2010,  12:38 Найти цитируемый пост)
главный недостаток в том, что сервер предоставляет информацию ТОЛЬКО по запросу пользователя
Если посмотреть на классиков (DCOM например), то там для этих случаев используют callback'и. Т.е. по сути локальный сервер на стороне пользователя + локальный пользователь на стороне сервера. 


PM MAIL   Вверх
mes
Дата 26.10.2010, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



а вот так примерно выглядит схема вызов<->вызов : 
Код


struct server {
   void login (client&) {  };
   void quit (client&) { }
   void chat_msg (client& c, std::string& phrase)
   {
        for each(other in all_clients)
        {
           if (other != c)
             client.on_chat_msg(chat_msg_t(c.name, phrase));
        }
   }
};

class client {
   void login ()    { m_server.login(*this); }
   void quit ()     { m_server.quit(*this); }  
   void chat_msg () { m_server.chat_msg(*this, "hallo"); }
   
   void on_login ()  { std::cout << "login ok "; }
   void on_quit  ()  { std::cout << "bye bye "; }
   void on_chat_msg (chat_msg_t m)
   {
     std::cout <<"from " << m.user_name << ": " << m.phrase;   
   }
      
   client(server&s) : m_server(s) {}
   
   server& m_server;
};


Добавлено @ 12:48
Цитата(xvr @  26.10.2010,  11:42 Найти цитируемый пост)
Если посмотреть на классиков (DCOM например), то там для этих случаев используют callback'и.

не знаю как в там в DCOM, но фактически асинхронные callback`и я и предлагаю.. 
 smile 
только вот НЕ с соотношением один вызов один каллбяк )

Это сообщение отредактировал(а) mes - 26.10.2010, 12:50


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



что-то не въезжаю.. откуда на стороне клиента может взяться сервер, и на стороне сервера клиент? кто тогда является сервером?
PM WWW   Вверх
mes
Дата 26.10.2010, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



правда справедливость названия  каллбяков в данном случае условна и зависит от способа рассмотрения..

Добавлено @ 12:52
Цитата(boostcoder @  26.10.2010,  11:50 Найти цитируемый пост)
что-то не въезжаю.. откуда на стороне клиента может взяться сервер, и на стороне сервера клиент? кто тогда является сервером? 

есть локальный сервер и удаленный smile

Добавлено @ 12:52
с клиентом то же самое )

Добавлено @ 12:59
boostcoder, в общем чтоб не путаться
 если информация содержится/накапливается на сервере а клиент ее должен считать, то Ваш способ подходит
если нужна возможность непосредственного взаимодействия клиента с клиентами или ж просто нужна возможность уведомления от сервера в независимости от запроса клиента то не подойдет. 


Это сообщение отредактировал(а) mes - 26.10.2010, 12:59


--------------------
PM MAIL WWW   Вверх
xvr
Дата 26.10.2010, 13:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mes @  26.10.2010,  12:46 Найти цитируемый пост)
не знаю как в там в DCOM,
Один в один с твоим предложением  smile 

Цитата(boostcoder @  26.10.2010,  12:50 Найти цитируемый пост)
кто тогда является сервером? 
Оба. Равно как и клиентом, тоже оба.


PM MAIL   Вверх
boostcoder
Дата 26.10.2010, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  12:51 Найти цитируемый пост)
если нужна возможность непосредственного взаимодействия клиента с клиентами или ж просто нужна возможность уведомления от сервера в независимости от запроса клиента то не подойдет.

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

Цитата(xvr @  26.10.2010,  13:00 Найти цитируемый пост)
Оба. Равно как и клиентом, тоже оба.

т.е. чтоб скомпилить клиентскую сторону, должна быть доступна реализация сервера, и на оборот? я правильно понял?
PM WWW   Вверх
mes
Дата 26.10.2010, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(xvr @  26.10.2010,  12:00 Найти цитируемый пост)
Оба. Равно как и клиентом, тоже оба.

вот например фирма выполняет заказ.. она в этот момент сервер, а заказчик клиент, 
а когда фирма высылает ему счет для оплаты, то заказчик сервер, а фирма клиент smile
т.е. все зависит от темы рассмотрения.. 
smile

Добавлено @ 13:11
Цитата(boostcoder @  26.10.2010,  12:06 Найти цитируемый пост)
т.е. чтоб скомпилить клиентскую сторону, должна быть доступна реализация сервера, и на оборот? я правильно понял? 

не совсем так.. клиентский клиент и клиентский сервер, несколько (а может и совершенно) другие чем серверный сервер и серверный клиент smile
smile

Добавлено @ 13:11
все зависит от исполнения.. smile

Добавлено @ 13:14
boostcoder, вот с точки зрения основной идеи вашей программы, (не знаю что там но допустим чат)
сервер будет сервером вашего чата, а клиент, клиентом вашего чата,
но и тот и другой могут иметь серверы удаленых вызовов.. 


Это сообщение отредактировал(а) mes - 26.10.2010, 13:15


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



т.е. мне нужно сейчас разделить реализацию сервера и клиента на две части.
сервер:
1. класс с аксэптором слушающим порт(КАСП).
2. класс взаимодействующий с сокетом клиента(КВСК).

клиент:
1. класс взаимодействующий с сокетом сервера(КВСС).
2. сериализатор/десериализатор команд(СДК).

мысли в слух..
на стороне сервера создаем объект КАСП и СДК. КАСП используется по назначению, в то время, как СДК используется для реализации обратных вызовов клиента.
на стороне клиента создаем объект КВСС и КВСК. КВСС используется по назначению, в то время, как КВСК используется 

запутался..

Добавлено через 55 секунд
в таком случае, нужно два соединения? одно клиента-с-сервером, второе сервера-с-клиентом? так?
PM WWW   Вверх
mes
Дата 26.10.2010, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  12:26 Найти цитируемый пост)
одно клиента-с-сервером, второе сервера-с-клиентом? так? 

сокет-соединение ? нет одно .. 
остальное еще не прочел

Добавлено @ 13:33
Цитата(boostcoder @  26.10.2010,  12:26 Найти цитируемый пост)
сейчас разделить реализацию сервера и клиента на две части.

я б сказал не так :
есть сокет соединение 
есть rpc соединение 
и само исполнение

естессвенно у каждого модуля(сервер или клинт) своя реализация каждого уровня.. общие только библиотеки.. 

Это сообщение отредактировал(а) mes - 26.10.2010, 13:36


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



..не понимаю..

может обратные вызовы реализовать следующим образом:
у клиента добавить метод типа "set_callback(int id, function)", где id - идентификатор колбэка, function - объект указывающий на функцию/метод на стороне клиента который будет вызываться. т.е. при вызове set_callback() указанный идентификатор регистрируется на сервере. в то время, на сервере добавить метод типа "callback(id, args...)". где id - идентификатор вызываемого на стороне клиента метода. клиент в свою очередь, должен уметь отличать ответы сервера на свои запросы, от вызовов колбэков.

как такая идея?
PM WWW   Вверх
mes
Дата 26.10.2010, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  12:53 Найти цитируемый пост)
как такая идея? 

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

поставленная задача:  распределять сообщения по исполнителям..
на тек момент одно сообщение, один исполнитель..
предполагается, что набор исполнителей представляют собой один композиционный объект
допустим есть такие сообщения :
Код

struct notice { enum { id = 0 }; };
struct login  { enum { id = 1 }; };
struct quit   { enum { id = 2 }; };
struct ping   { enum { id = 3 }; };
struct pong   { enum { id = 4 }; };

такой набор исполнителей 
Код

struct auth_handler {
     void on_login  (login const&)  { std::cout << ".auth.login" << std::endl; }
     void on_quit   (quit  const&)  { std::cout << ".auth.quit" << std::endl;  }
};

struct pingpong_handler
{
     void on_ping   (ping const&)   { std::cout << ".pp.ping" << std::endl; }
     void on_pong   (pong const&)   { std::cout << ".pp.pong" << std::endl; }
};

struct recipient
{
   void on_notice (notice const&) { std::cout << ".notice" << std::endl; }
   
   auth_handler       auth;
   pingpong_handler   pingpong;
      
};

диспетчера сообщений :
Код

struct idispatcher
{
   virtual void dispatch (recipient& r, void const* raw_msg )=0;
};

#define DEF_DISP(name, typ, func) \
struct name : idispatcher \
{ \
    virtual void dispatch (recipient& r, void const* raw_msg ) \
    { \
       r func (*static_cast<typ const*>(raw_msg)); \
    } \
};
DEF_DISP(login_dispatcher,  login,  .auth.on_login );
DEF_DISP(quit_dispatcher,   quit,   .auth.on_quit );
DEF_DISP(ping_dispatcher,   ping,   .pingpong.on_ping );
DEF_DISP(pong_dispatcher,   pong,   .pingpong.on_pong );
DEF_DISP(notice_dispatcher, notice, .on_notice );


условный сервер приемки сообщений
Код

idispatcher * disp_table[5] = 
{
  new notice_dispatcher,
  new login_dispatcher,
  new quit_dispatcher,
  new ping_dispatcher,
  new pong_dispatcher
};

void dispatch (size_t msg_id, void const* raw_msg )
{
     disp_table[msg_id]->dispatch(g_recipient, raw_msg);
}

отправитель :
Код

template<class T>
void send (T const& msg)
{
    dispatch (T::id, &msg);
}


тестовый пример :
Код

int main ()
{
    send (login());
    send (ping());
    send (pong());    
    send (notice());
    send (quit());
}

и вывод
Цитата

.auth.login
.pp.ping
.pp.pong
.notice
.auth.quit


http://liveworkspace.org/code/5afd22007254...ad429549e89fe69

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



--------------------
PM MAIL WWW   Вверх
mes
Дата 26.10.2010, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mes @  26.10.2010,  13:39 Найти цитируемый пост)
сейчас попробую доработать, чтоб одно сообщение могло в нескольких местах отрабатывать..

чего то заклинил, можно ведь  вместо карты(массива) диспетчеров просто сделать мультикарту.. 
smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  14:39 Найти цитируемый пост)
и так у нас есть как клиент так и сервер могут отправлять вызовы
т.е. каждый из них является то отправителем то получателем.. 

знаков препинания не хватает..смысла не понял...

Добавлено через 25 секунд
Цитата(mes @  26.10.2010,  15:05 Найти цитируемый пост)
можно ведь  вместо карты(массива) диспетчеров просто сделать мультикарту.. 

ага

Добавлено через 55 секунд
по остальному - вникаю в суть...
PM WWW   Вверх
mes
Дата 26.10.2010, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  14:23 Найти цитируемый пост)
знаков препинания не хватает..смысла не понял...


Цитата(mes @  26.10.2010,  13:39 Найти цитируемый пост)
и так у нас есть:
 как клиент, так и сервер могут отправлять вызовы, т.е. каждый из них является то отправителем, то получателем.. 


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


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @ 26.10.2010,  15:27)
Цитата(boostcoder @  26.10.2010,  14:23 Найти цитируемый пост)
знаков препинания не хватает..смысла не понял...


Цитата(mes @  26.10.2010,  13:39 Найти цитируемый пост)
и так у нас есть:
 как клиент, так и сервер могут отправлять вызовы, т.е. каждый из них является то отправителем, то получателем.. 


Добавлено @ 15:28
т.е. приведенный код будет как на севере, так и на клиенте, только для своих групп сообщений

ага. понял... щас..
PM WWW   Вверх
mes
Дата 26.10.2010, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mes @  26.10.2010,  14:05 Найти цитируемый пост)
можно ведь  вместо карты(массива) диспетчеров просто сделать мультикарту.. 

или отделить функциональный вызов от диспатчеризации
т.е. вместо макроса DEF_DISP и всего с его участием, пишем что то типа такого :

Код

// библиотечная часть
template<class T>
struct dispatcher : idispatcher
{ 
    virtual void dispatch (recipient& r, void const* raw_msg ) 
    { 
       func (r, *static_cast<typ const*>(raw_msg)); 
    }
    dispatcher (..)..
    boost::function<void (*) (recipient&, T const& msg)> func;
};

Код

// пользовательская
register ( dispather<login> 
    ([] (recipient& r, login& msg ) 
    {   
         r      .on_notice(msg);
         r.auth .on_notice (msg);
         ...
    }) 
);

могут быть ошибки.. с лямбдами пока еще не приходилось работать.. 

Это сообщение отредактировал(а) mes - 26.10.2010, 15:56


--------------------
PM MAIL WWW   Вверх
mes
Дата 26.10.2010, 18:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



вот доработал немного :
http://liveworkspace.org/code/17eb2d53ecbb...5b334c82dbf190e

Добавлено @ 18:11
а вот чистый пример, без классов исполнителей..  
http://liveworkspace.org/code/6e7e20117c85...4e7a337ac958087

Добавлено @ 18:13
вот пока объяснял сам разобрался как происходить должно... 
smile 

если что осталось непонятным, спрашивайте 
smile



Это сообщение отредактировал(а) mes - 26.10.2010, 18:45


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 19:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



последними двумя примерами, вы меня окончательно запутали..
я так понял, что сейчас мы решаем ассоциирование команд с разными интерфейсами? или что?
до этого, я думал что сейчас мы решаем как создавать исполнителей на стороне сервера по запросу клиента.
а до этого, думал что мы решали каким образом реализовать колбэки.
и это все за один день smile 

Это сообщение отредактировал(а) boostcoder - 26.10.2010, 19:51
PM WWW   Вверх
mes
Дата 26.10.2010, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  18:50 Найти цитируемый пост)
последними двумя примерами, вы меня окончательно запутали..

так по сути там то же самое.. просто лишние детали выкорчивались.. 


Цитата(boostcoder @  26.10.2010,  18:50 Найти цитируемый пост)
я так понял, что сейчас мы решаем ассоциирование команд с разными интерфейсами? или что?

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

Добавлено через 1 минуту и 9 секунд
Цитата(boostcoder @  26.10.2010,  18:50 Найти цитируемый пост)
до этого, я думал что сейчас мы решаем как создавать исполнителей на стороне сервера по запросу клиента.

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

Добавлено через 1 минуту и 49 секунд
Цитата(boostcoder @  26.10.2010,  18:50 Найти цитируемый пост)
а до этого, думал что мы решали каким образом реализовать колбэки.

и это то же.. как подзадачу smile

Добавлено через 3 минуты и 24 секунды
сейчас надо определиться с какой стороны идти.. 


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 20:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, я вам очень благодарен..но дело в том, что я и в правду запутался.
если вас не затруднит, опишите пожалуйста, какой вы видите реализацию, словами. для дурака так сказать.


очень благодарен вам за то что вы на протяжении всей темы помогаете мне. спасибо.


PM WWW   Вверх
mes
Дата 26.10.2010, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  19:28 Найти цитируемый пост)
.но дело в том, что я и в правду запутался.

это я понял.. поэтому и написал :
Цитата(mes @  26.10.2010,  19:20 Найти цитируемый пост)
сейчас надо определиться с какой стороны идти..  

вот сижу и думаю, с чего начать, что у вас уже есть, и где возникла  путаница...

Добавлено @ 20:42
ну например клиент может выглядить так :
Код

rpc::socket_connection<my_protocol> connection;
connection.register ([](login_result const& msg){ std::cout <<(msg.ok ?  "login ok  " : "login fail") << std::endl; });
connection << login("boostcoder", "pass");

тут есть вопросы ?

пояснения :
my_protocol  это traits- структура, содержащая список сообщений, допустимых для передачи по соединению.. 
register() - установка делегата
оператор <<  - отправка сообщения в сеть




Цитата(boostcoder @  26.10.2010,  19:28 Найти цитируемый пост)
вы на протяжении всей темы 

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

smile

Это сообщение отредактировал(а) mes - 26.10.2010, 20:49


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 20:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



сейчас есть рабочая реализация сервера и клиента, позволяющая декларировать в удобном(абстрактном) для пользователя синтаксисе команды запросов/ответов + генератор всей подноготной необходимой серверу чтоб знать, какая команда с каким обработчиком ассоциирована.

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

приоритеты возможно не в том порядке, т.к. возможно одно зависит от другого.

вот.

PM WWW   Вверх
mes
Дата 26.10.2010, 20:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  19:49 Найти цитируемый пост)
сейчас есть рабочая реализация сервера и клиента, позволяющая декларировать в удобном(абстрактном) для пользователя синтаксисе команды запросов/ответов + генератор всей подноготной необходимой серверу чтоб знать, какая команда с каким обработчиком ассоциирована.


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

Добавлено через 44 секунды
Цитата(boostcoder @  26.10.2010,  19:49 Найти цитируемый пост)
первым и очевидным недостатком текущей реализации является то, что сервер привязан к конкретному классу обработчиков. и не имеет возможности в рантайме их менять/создавать.

т.е. с приемом/передачей одного сообщения у вас проблем нет ?



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



под обработчиком подразумеваю это:
Код

struct i_registration_api {
   virtual void user_exists_handler ( user_exists_result&, const user_exists_query& ) = 0;
   virtual void registration_handler ( registration_result&, const registration_query& ) = 0;
   virtual void activation_handler ( activation_result&, const activation_query& ) = 0;
   i_registration_api () {
      _map[0] = i_invoker_ptr( new invoker< i_registration_api, user_exists >(this, &i_registration_api::user_exists_handler ) );
      _map[1] = i_invoker_ptr( new invoker< i_registration_api, registration >(this, &i_registration_api::registration_handler ) );
      _map[2] = i_invoker_ptr( new invoker< i_registration_api, activation >(this, &i_registration_api::activation_handler ) );
   }
   // этот метод дергает сервер. наверное его нужно спрятать от юзера...
   virtual void proxy_call(constants::header_packet& h, constants::body_packet& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }
private:
   std::map<int, i_invoker_ptr> _map;
};

т.е. это конечный код генерируемый метагенератором.

на стороне сервера используется так:
Код

struct registration_api: i_registration_api {
   // реализуем виртуальные методы
   // т.е. юзеру ничего более о внутренностях реализации знать не надо.
   // он всего лишь должен реализовать чистовиртуальные методы. все.
};

server<registration_api> server(...); // все. сервер может работать только с этим типом.


на стороне клиента:
Код

client client(argv[1], std::atoi(argv[2]));

user_exists::result_type ret = client.query<user_exists>("John", "[email protected]");
std::cout << ret->message() << ", " << ret->code() << std::endl;


вот.
вроде ничего не упустил.

Добавлено @ 21:01
Цитата(mes @  26.10.2010,  20:51 Найти цитируемый пост)
т.е. с приемом/передачей одного сообщения у вас проблем нет ?

не только одного. многих.
вот реальный пример теста:
Код

      client client(argv[1], std::atoi(argv[2]));
      while ( true ) {
         user_exists::result_type ret = client.query<user_exists>("John", "[email protected]");
         std::cout << ret->message() << ", " << ret->code() << std::endl;

         registration::result_type ret1 = client.query<registration>("John", "[email protected]");
         std::cout << ret1->message() << ", " << ret1->code() << std::endl;

         activation::result_type ret2 = client.query<activation>("John", "234566534");
         std::cout << ret2->message() << ", " << ret2->code() << std::endl;

      }


зы
у меня есть приватное SVN хранилище, может быть дать вам доступ? это значительно облегчит понимание.


Это сообщение отредактировал(а) boostcoder - 26.10.2010, 21:09
PM WWW   Вверх
mes
Дата 26.10.2010, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



вот опять вернулись к самому началу.. вы все время избегаете этого факта..
для создания синхроного запрос/ответ вы идете на искусственные ограничения... 
если  нужна будет синхронность ее лучше организовать внешним слоем...

я все ж настаиваю на системе вызов<->вызов, так как с каждой минутой все более уверен, что именно она вам нужна..

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

Добавлено через 3 минуты и 18 секунд
Цитата(boostcoder @  26.10.2010,  19:58 Найти цитируемый пост)
не только одного. многих.

для начала все ж дождусь ответа, готовы ли следовать предложеной схеме и отказаться от своей ? 




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  21:09 Найти цитируемый пост)
я все ж настаиваю на системе вызов<->вызов, так как с каждой минутой все более уверен, что именно она вам нужна..

я ведь не спорю. просто я не могу понять что именно вы подразумеваете под этим. как это должно выглядеть? потому я писал выше, что запутался в задачах. что сейчас нужно изменить в уже имеющемся коде?

да нет же. в данный момент, я именно в ступоре. даже не могу понять что делать дальше.

Добавлено через 50 секунд
Цитата(mes @  26.10.2010,  21:09 Найти цитируемый пост)
готовы ли следовать предложеной схеме и отказаться от своей ? 

да. просто объясните, что и как должно быть?
PM WWW   Вверх
mes
Дата 26.10.2010, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



у вас есть возможность проверять и клиент и сервер ? 
то есть как я понял у Вас есть (если все лишнее выкинуть) фактически пустые клиент и сервер на основе сокетов ?

Добавлено @ 21:16
задаю вопросы по частям чтоб не уйти в сторону.. 

Это сообщение отредактировал(а) mes - 26.10.2010, 21:17


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 21:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  21:16 Найти цитируемый пост)
у вас есть возможность проверять и клиент и сервер ? 
то есть как я понял у Вас есть (если все выкинуть) фактически пустые клиент и сервер на основе сокетов ?

да.
сейчас это пустой каркас. для тестов, обработчики заполнил хламом:
Код

struct registration_api: i_registration_api {
   virtual void user_exists_handler(user_exists_result& r, const user_exists_query&) {
      r.code = rand()%33;
      r.message = "yes, John already registered " + boost::lexical_cast<std::string>(rand()%13) + " times";
   }

   virtual void registration_handler(registration_result& r, const registration_query&) {
      r.code = rand()%7;
      r.message = "you succesfuly registered";
   }

   virtual void activation_handler(activation_result& r, const activation_query&) {
      r.code = rand()%3;
      r.message = "please check your e-mail";
   }
};


PM WWW   Вверх
mes
Дата 26.10.2010, 21:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  20:19 Найти цитируемый пост)
сейчас это пустой каркас. для тестов, обработчики заполнил хламом:

выкиньте хлам.. 

добавьте две структуры query и result с разными id
сделайте два сендера один может отправлять query в сокет, другой result
а также два простых получателя, (для каждого по одному сообщению) печатающих допустим id
и разместите соответсвенно одну пару на клиенте , другую на сервере..

ничего лишнего, только самое необходимое.. 

жду (результата или вопросов) smile



Это сообщение отредактировал(а) mes - 26.10.2010, 21:29


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 21:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  21:28 Найти цитируемый пост)
выкиньте хлам.. 

т.е. из тела обработчиков? сами обработчики оставить пустыми?

Цитата(mes @  26.10.2010,  21:28 Найти цитируемый пост)
добавьте две структуры query и result с разными id

в данный момент, структуры(запросы и ответы) генерируются кодогенератором.
так:
Код

DECLARE_HANDLER_CLASS(
   // abstract class name
   registration_api,
   // check if user with this nick and email already exists
   ((user_exists, // это команда
      ((query, // это тип запроса
        ((std::string, nick))
        ((std::string, email))
      ))
      ((result, // это тип ответа
         ((int, code))
         ((std::string, message))
      ))
   ))
   // registration query
   ((registration, // это команда
      ((query,
         ((std::string, nick))
         ((std::string, email))
      ))
      ((result,
         ((std::string, message))
         ((int, code))
      ))
   ))
   // activation query
   ((activation, // это команда
      ((query,
         ((std::string, nick))
         ((std::string, code))
      ))
      ((result,
         ((std::string, message))
         ((int, code))
      ))
   ))
)


т.е. код который вы видите выше, генерируется этим макросом.
т.е. изменить этот макрос так, чтоб в нем были две структуры? или две команды? команда - состоит из двух структур: 1)запрос, 2)ответ.
так как?

Цитата(mes @  26.10.2010,  21:28 Найти цитируемый пост)
сделайте два сендера один может отправлять query в сокет, другой result

на стороне клиента?
т.е. создать два объекта типа client?
или как?

Цитата(mes @  26.10.2010,  21:28 Найти цитируемый пост)
и размести соответсвенно одну пару на клиенте , другую на сервере..

т.е. на сервере один сендер и один получатель? на клиенте так же?

PM WWW   Вверх
mes
Дата 26.10.2010, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  20:40 Найти цитируемый пост)
т.е. из тела обработчиков? сами обработчики оставить пустыми?

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

Добавлено через 31 секунду
Цитата(boostcoder @  26.10.2010,  20:40 Найти цитируемый пост)
т.е. на сервере один сендер и один получатель? на клиенте так же?

ага smile



--------------------
PM MAIL WWW   Вверх
mes
Дата 26.10.2010, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



можно даже не два объекта, а две функции 
вот к примеру :
Код

//client
struct connection_t : socket_evthandler 
{
     template<class T>
     void send ( T const&);
  protected:
      ...
     void receive (..)
     {
          ..
         std::cout << "msg_id" << ..
     }
 private:
  socket_t     socket;
};

терь нужно оживить это...

на клиенте и на севере подобная конструкция 
чтоб клиент отправлял серверу query, а тот в ответ result.. 

и еще раз, никаких макросов и кодогенераторов на этом этапе.. 

Это сообщение отредактировал(а) mes - 26.10.2010, 22:31


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 22:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ок. понял. сделаю.

Добавлено через 9 минут и 29 секунд
чтение/запись сделать асинхронными?
PM WWW   Вверх
boostcoder
Дата 26.10.2010, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

Добавлено через 52 секунды
идея smile 
PM WWW   Вверх
mes
Дата 26.10.2010, 23:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  21:40 Найти цитируемый пост)
чтение/запись сделать асинхронными? 

ага smile

Цитата(boostcoder @  26.10.2010,  21:55 Найти цитируемый пост)
если я все верно понял, то вы хотите реализовать запись и чтение в один сокет на каждой стороне?

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

Цитата(boostcoder @  26.10.2010,  21:55 Найти цитируемый пост)
 т.е. когда клиент записывает в сокет, на стороне сервера получаем событие записи и читаем из сокета. в то время, если сервер пишет, то событие записи получаем на стороне клиента.

ага smile
я даже боюсь представить как у вас было раньше.. smile




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  26.10.2010,  23:03 Найти цитируемый пост)
я даже боюсь представить как у вас было раньше..

 smile 
сервер создавал сокет при подключении и ждал записи со стороны клиента. клиент, после того как записал серверу, ожидал записи со стороны сервера smile 
PM WWW   Вверх
mes
Дата 26.10.2010, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  26.10.2010,  22:11 Найти цитируемый пост)
сервер создавал сокет при подключении и ждал записи со стороны клиента. клиент, после того как записал серверу, ожидал записи со стороны сервера   

ну в принципе я так и подумал.. просто не смог представить, как вы даже чат на таком реализовывать будете..
( а по видимым кускам, там нечто по сложнее чем чистый чат) smile

зато хоть  все стало становиться на свои места... понятно что вставляло палки в колеса понимания smile




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 26.10.2010, 23:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



да..с проектированием у меня есть проблемы. исправляюсь. читаю умные книжки.
наверное еще пол часика и будет код.
PM WWW   Вверх
boostcoder
Дата 27.10.2010, 02:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

сервер:
Код

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>

const int bufsize = 1024;
typedef boost::array<char, bufsize> buffer;

/***************************************************************************/

struct server {
   server(boost::asio::io_service& ios, boost::uint16_t port)
      :_acceptor(ios, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
      _socket(ios),
      _idx(0)
   {
      _acceptor.async_accept(_socket,
         boost::bind(&server::handle_accept, this, boost::asio::placeholders::error)
      );
   }

   ~server() {
      std::cout << "destructing server" << std::endl;
   }

   void handle_accept(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << "server: incoming connection from: " << _socket.remote_endpoint().address().to_string() << std::endl;
         start_read();
         start_write();
      } else {
         std::cout << "server: error on server accept" << std::endl;
      }
   }

   void start_read() {
      boost::asio::async_read(_socket,
         boost::asio::buffer(_inbuffer, _inbuffer.size()),
         boost::bind(&server::read_handler, this, boost::asio::placeholders::error)
      );
   }

   void start_write() {
      sprintf(_outbuffer.begin(), "%d", _idx++);
      boost::asio::async_write(_socket,
         boost::asio::buffer(_outbuffer, _outbuffer.size()),
         boost::bind(&server::write_handler, this, boost::asio::placeholders::error)
      );
   }

   void read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << "server: read message form client \"" << _inbuffer.begin() << "\"" << std::endl;
      } else {
         std::cout << "server: read from client error" << std::endl;
      }
      start_read();
   }

   void write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << "server: message writen to client \"" << _outbuffer.begin() << "\"" << std::endl;
      } else {
         std::cout << "server: error on writing to client" << std::endl;
      }
      start_write();
   }

private:
   boost::asio::ip::tcp::acceptor _acceptor;
   boost::asio::ip::tcp::socket _socket;
   int _idx;
   buffer _inbuffer;
   buffer _outbuffer;
};

/***************************************************************************/

int main() {
   try {
      boost::asio::io_service ios;
      server server(ios, 44550);
      ios.run();
   } catch (const std::exception& e) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
}

/***************************************************************************/


собирать так:
Цитата

g++ -oserver server.cpp -lboost_system


клиент:
Код

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>

const int bufsize = 1024;
typedef boost::array<char, bufsize> buffer;

/***************************************************************************/
struct client {
   client(boost::asio::io_service& ios, const char* ip, boost::uint16_t port)
      :_socket(ios),
      _idx(0)
   {
      boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
      _socket.connect(endpoint);
      std::cout << "client: connected to server" << std::endl;
      /**  */
      start_write();
      start_read();
   }

   ~client() {
      _socket.close();
      std::cout << "destructing client" << std::endl;
   }

   void start_write() {
      sprintf(_outbuffer.begin(), "%d", _idx++);
      boost::asio::async_write(_socket,
         boost::asio::buffer(_outbuffer, _outbuffer.size()),
         boost::bind(&client::write_handler, this, boost::asio::placeholders::error)
      );
   }

   void start_read() {
      boost::asio::async_read(_socket,
         boost::asio::buffer(_inbuffer, _inbuffer.size()),
         boost::bind(&client::read_handler, this, boost::asio::placeholders::error)
      );
   }

   void write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << "client: message writen to server \"" << _outbuffer.begin() << "\"" << std::endl;
      } else {
         std::cout << "client: error on writing to server" << std::endl;
      }
      start_write();
   }

   void read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << "client: message read from server \"" << _inbuffer.begin() << "\""<< std::endl;
      } else {
         std::cout << "client: error read from server" << std::endl;
      }
      start_read();
   }

private:
   boost::asio::ip::tcp::socket _socket;
   int _idx;
   buffer _inbuffer;
   buffer _outbuffer;
};

/***************************************************************************/

int main() {
   try {
      boost::asio::io_service ios;
      client client(ios, "127.0.0.1", 44550);
      ios.run();
   } catch (const std::exception& e) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
}

/***************************************************************************/


собирать так:
Цитата

g++ -oclient client.cpp -lboost_system

PM WWW   Вверх
mes
Дата 27.10.2010, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  27.10.2010,  01:33 Найти цитируемый пост)
вот.
даже работает  

 smile 

итак старт положен..  "сырые" данные можете отправлять.. чтоб не путаться назовем объекты этого уровня net_client и net_server..

теперь создаем еще одного clienta, который будет посредством net_client`a отправлять уже типизированные сообщения.. 
и еще один сервер, который на основе net_servera будет по id в карте вызывать нужный диспетчер
для начала диспетчер такого вида :
Код

  struct dispatcher { void dispatch () { std::cout <<"dispatched"; } };



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 27.10.2010, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

зы
вот теперь я точно понял идею )

PM WWW   Вверх
mes
Дата 27.10.2010, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  27.10.2010,  14:59 Найти цитируемый пост)
в следующем варианте, и клиент и сервер, изначально должны находится в режиме чтения. так?

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



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 27.10.2010, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



т.е. после подключения, клиент и сервер становятся в операцию асинхронного чтения на сокете? полагаю, так логичнее. т.к. изначально мы не зависим от того, кто ведущий а кто ведомый. и любой из них может первым послать пакет.
PM WWW   Вверх
mes
Дата 27.10.2010, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mes @  27.10.2010,  07:51 Найти цитируемый пост)
и еще один сервер, который на основе net_servera будет по id в карте вызывать нужный диспетчер

вобще-то это уже будет не сервер..а сессия (или удаленный client.. ) но так как у нас (насколько я понял) сервер на одного клиента, то пока пойдет, потом будет виднее где подправить smile

Добавлено @ 16:31
Цитата(boostcoder @  27.10.2010,  15:29 Найти цитируемый пост)
и любой из них может первым послать пакет. 

 smile 

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

Добавлено через 3 минуты и 9 секунд
Цитата(boostcoder @  27.10.2010,  15:29 Найти цитируемый пост)
 т.к. изначально мы не зависим от того, кто ведущий а кто ведомый

значит все таки столько страниц темы были не напрасны  smile 

Это сообщение отредактировал(а) mes - 27.10.2010, 16:32


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 27.10.2010, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

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

Добавлено через 7 минут и 38 секунд
Цитата(mes @  27.10.2010,  16:30 Найти цитируемый пост)
значит все таки столько страниц темы были не напрасны

 smile 
PM WWW   Вверх
mes
Дата 27.10.2010, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  27.10.2010,  15:34 Найти цитируемый пост)
к примеру: клиент подключился к серверу. оба читают из сокета.
сервер производит запись. но т.к. клиент ожидает записи в сокет, он читает пакет, снова становится в режим чтения, что-то выполняет с прочитанным пакетом.
так?

висят себе два сокета никого не трогют, в один написали, друг подал сигнал, и его прочитали.. 
smile

Добавлено через 30 секунд
Цитата(boostcoder @  27.10.2010,  15:34 Найти цитируемый пост)
еще любопытно, каким образом можно реализовать пакеты двух типов? т.е. пакеты на которые нужно посылать ответ, и пакеты без ответов?

никаким образом этого не нужно ( и не придется) делать smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 27.10.2010, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  27.10.2010,  16:50 Найти цитируемый пост)
висят себе два сокета никого не трогют, в один написали, друг подал сигнал, и его прочитали.. 

ну да.

Цитата(mes @  27.10.2010,  16:50 Найти цитируемый пост)
никаким образом этого не нужно ( и не придется) делать

ок.

сейчас код выдам.

PM WWW   Вверх
boostcoder
Дата 28.10.2010, 00:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



если я все правильно понял, то вот.
код компилиться, но не завершен, т.к. некоторые моменты не ясны.
а именно:
1. клиент, при посылке команды, каким образом будет знать, на какую команду ждать ответа, а на какую нет?
2. серверу, чтоб послать ответ на какую-то команду, так же как и клиенту нужно знать, на какую команду отвечать, а на какую нет.

хидер:
Код


#include <iostream>
#include <memory>
#include <functional>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/lexical_cast.hpp>

/***************************************************************************/

static const boost::uint16_t  port = 44550;
static const char*            host = "127.0.0.1";

/***************************************************************************/

struct constants {
   enum { header_length = 12 };
   enum { body_length = 1024*32 };
   enum { client_server, server_client };
   typedef boost::array<char, header_length> header_buffer;
   typedef boost::array<char, body_length> body_buffer;
};

/***************************************************************************/

struct header_coders {
   struct header {
      boost::int32_t    id;
      boost::uint32_t   direction;
      boost::uint32_t   body_length;
   };

   template<typename T>
   static constants::header_buffer encode_header(const std::string& b) {
      constants::header_buffer header;
      sprintf(header.data(), "%04d%02d%06d", T::meta_id, T::meta_dir, b.length());
      return header;
   }

   static header decode_header(const constants::header_buffer& data) {
      header hdr;
      sscanf(data.data(), "%04d%02d%06d", &hdr.id, &hdr.direction, &hdr.body_length);
      return hdr;
   }
};

/***************************************************************************/

inline std::ostream& operator<< (std::ostream& os, const header_coders::header& hdr) {
   os << "id:" << hdr.id << ", dir:" << hdr.direction << ", len:" << hdr.body_length << std::endl;
   return os;
}

/***************************************************************************/

struct notice { enum { id = 0 }; };
struct login  { enum { id = 1 }; };
struct quit   { enum { id = 2 }; };
struct ping   { enum { id = 3 }; };
struct pong   { enum { id = 4 }; };

/***************************************************************************/

struct i_invoker {
   virtual void dispatch(constants::header_buffer&, constants::body_buffer&) = 0;
};
typedef std::shared_ptr<i_invoker> i_invoker_ptr;

template<typename T, typename C>
struct invoker: i_invoker {
   typedef void(C::*handler_t)(T&);

   invoker(C* p, handler_t h):_this(p),_handler(h) {}

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      T data;
      deserializer(data, h, b);
      (*_this.*_handler)(data);
      serializer(h, b, data);
   }

private:
   void deserializer(T& t, const constants::header_buffer&, const constants::body_buffer&) {
      t = T();
   }

   void serializer(constants::header_buffer&, constants::body_buffer&, const T&) {
   }

private:
   C* _this;
   handler_t _handler;
};

/***************************************************************************/

struct i_implementation {
   virtual void notice_handler(notice&) = 0;
   virtual void login_handler(login&) = 0;
   virtual void quit_handler(quit&) = 0;
   virtual void ping_handler(ping&) = 0;
   virtual void pong_handler(pong&) = 0;

   i_implementation() {
      _map[0] = i_invoker_ptr(new invoker<notice, i_implementation>(this, &i_implementation::notice_handler));
      _map[1] = i_invoker_ptr(new invoker<login, i_implementation>(this, &i_implementation::login_handler));
      _map[2] = i_invoker_ptr(new invoker<quit, i_implementation>(this, &i_implementation::quit_handler));
      _map[3] = i_invoker_ptr(new invoker<ping, i_implementation>(this, &i_implementation::ping_handler));
      _map[4] = i_invoker_ptr(new invoker<pong, i_implementation>(this, &i_implementation::pong_handler));
   }
   
   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      if ( _map.find(id) == _map.end() ) {
         throw std::runtime_error("for type::id(" + boost::lexical_cast<std::string>(id) + ") handler not registered!");
      }
      _map[id]->dispatch(h, b);
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

/***************************************************************************/


реализация:
Код


#include "header.hpp"

/***************************************************************************/

struct implementation: i_implementation {
   void notice_handler(notice&) {
      std::cout << "called: " << __PRETTY_FUNCTION__ << std::endl;
   }
   
   void login_handler(login&) {
      std::cout << "called: " << __PRETTY_FUNCTION__ << std::endl;
   }
   
   void quit_handler(quit&) {
      std::cout << "called: " << __PRETTY_FUNCTION__ << std::endl;
   }
   
   void ping_handler(ping&) {
      std::cout << "called: " << __PRETTY_FUNCTION__ << std::endl;
   }
   
   void pong_handler(pong&) {
      std::cout << "called: " << __PRETTY_FUNCTION__ << std::endl;
   }
};

/***************************************************************************/

struct server {
   server(boost::asio::io_service& ios, boost::uint16_t port)
      :_acceptor(ios, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
      _socket(ios),
      _idx(0),
      _impl(new implementation())
   {
      _acceptor.async_accept(_socket,
         boost::bind(&server::handle_accept, this, boost::asio::placeholders::error)
      );
   }

   ~server() {
      std::cout << "destructing server" << std::endl;
   }

   void handle_accept(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout
            << "server: incoming connection from: "
            << _socket.remote_endpoint().address().to_string() << std::endl;
         start_read();
      } else {
         std::cout << "server: error on server accept" << std::endl;
      }
   }

   void start_read() {
      boost::asio::async_read(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&server::header_read_handler, this, boost::asio::placeholders::error)
      );
   }

   void header_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         std::cout << header_coders::decode_header(_header) << std::endl;
         boost::asio::async_read(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&server::body_read_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "server: header read error" << std::endl;
      } 
   }

   void body_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         _impl->dispatch(_header, _body);
      } else {
      }
      start_read();
   }

   void start_write() {
      boost::asio::async_write(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&server::header_write_handler, this, boost::asio::placeholders::error)
      );
   }

   void header_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         boost::asio::async_read(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&server::body_write_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "server: header write error" << std::endl;
      }
      start_write();
   }

   void body_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
      } else {
      }
   }
   
   constants::header_buffer _header;
   constants::body_buffer _body;

private:
   boost::asio::ip::tcp::acceptor _acceptor;
   boost::asio::ip::tcp::socket _socket;
   int _idx;
   std::shared_ptr<implementation> _impl;
};

/***************************************************************************/

int main() {
   try {
      boost::asio::io_service ios;
      server server(ios, port);
      ios.run();
   } catch (const std::exception& e) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
}

/***************************************************************************/


PM WWW   Вверх
mes
Дата 28.10.2010, 08:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  27.10.2010,  23:21 Найти цитируемый пост)
1. клиент, при посылке команды, каким образом будет знать, на какую команду ждать ответа, а на какую нет?
2. серверу, чтоб послать ответ на какую-то команду, так же как и клиенту нужно знать, на какую команду отвечать, а на какую нет.

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

сейчас код гляну

Добавлено через 14 минут и 47 секунд
посмотрел.. как и предполагалось по вступительным вопросам к коду.. опять вставили свою лепту.. smile
ну в принципе ничего так, только надо  вытащить нужное, и избавиться от лишнего.. 



--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 08:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  27.10.2010,  23:21 Найти цитируемый пост)
struct i_implementation {

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

Цитата(boostcoder @  27.10.2010,  23:21 Найти цитируемый пост)
struct server {

Цитата(boostcoder @  27.10.2010,  23:21 Найти цитируемый пост)
  std::shared_ptr<implementation> _impl;

это у Вас моноблок получается.. нехорошо.. 

Цитата(boostcoder @  27.10.2010,  23:21 Найти цитируемый пост)
struct i_invoker {

к инвокерам претензий в принципе нет



--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 09:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



пока оставим сервер в покое.. принимает - молодец, с него пока хватит.. 
(только к клиенту этот подход не применять, и не отходить от нашего нижепредложенного плана )
рассмотрим net_client... 
нам важны сейчас две его функции , отправки и приема сырых данных.. 
сырые данные (исходя из кода) у нас выражены как (header&, body&)
на клиентена надо добавить два объекта.. rpc_sender и rpc_receiver
выглядят так
Код

struct rpc_sender {
  
   template<typename T>
   void send (const T&) {  ... raw_send (.. , ..);  }
   std::function<void(header&, body&)> raw_send;
};

Код

struct rpc_receiver {
  
   void dispatch (header&, body&) {
         std::cout << ..
   }
};

привязка к net_clientу посредством bind. 
для проверки можно связать сендер и ресивер непосредственно .. 

и еще раз ничего лишнего ! smile
фактически только реализовать сендер и привязку.. 

Это сообщение отредактировал(а) mes - 28.10.2010, 09:17


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 09:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  08:36 Найти цитируемый пост)
опять )) ничего лишнего ! ) только то что было в задании )

это правда. я забежал вперед. просто в момент написания, мне казалось что идею я понял целиком..но когда дошло дело до отправки ответа, я понял, что ничего не понял..

Цитата(mes @  28.10.2010,  08:36 Найти цитируемый пост)
сервер не посылает ответ, как таковой, он просто принимает команды и работает и побрабатывает их..
если ему когда нибудь (в зависмости от логики обработки, и независимо от приема команды клиента) захочеться послать клиенту команду, он просто ее посылает.. 

т.е. команды для клиента и сервера разные? не связанные между собой?

Цитата(mes @  28.10.2010,  08:36 Найти цитируемый пост)
надо  вытащить нужное, и избавиться от лишнего.. 

от чего именно избавится?

Цитата(mes @  28.10.2010,  08:59 Найти цитируемый пост)
по коду я понял, что у вас предполагается одинаковая база как для сервера, так и для клиента?
это жесткая привязка, которая может заставить пользователя писать костыль.. 

это именно тот момент, из-за которого я недописал реализацию.

Цитата(mes @  28.10.2010,  08:59 Найти цитируемый пост)
это у Вас моноблок получается.. нехорошо.. 

ага.

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

Добавлено через 1 минуту и 20 секунд
по последнему: вроде понял..

Добавлено через 3 минуты и 2 секунды
Цитата(boostcoder @  28.10.2010,  09:51 Найти цитируемый пост)
код приведенный выше, так, чтоб в нем небыло ничего лишнего?

т.е. мой код.
PM WWW   Вверх
mes
Дата 28.10.2010, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  08:51 Найти цитируемый пост)
не могли бы вы изменить код приведенный выше, так, чтоб в нем небыло ничего лишнего? т.к. я не очень понимаю что именно я должен сделать..


Цитата(mes @  28.10.2010,  08:17 Найти цитируемый пост)
пока оставим сервер в покое.. принимает - молодец, с него пока хватит.. 

Цитата(mes @  28.10.2010,  08:17 Найти цитируемый пост)
фактически только реализовать сендер и привязку.. 

 smile 


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ок.

Добавлено через 3 минуты и 48 секунд
Цитата(mes @  28.10.2010,  09:17 Найти цитируемый пост)
нам важны сейчас две его функции , отправки и приема сырых данных.. 

по приему данных все ок. в коде сервера, в строке 77, заголовок и тело прочитаны. можно диспетчеризировать.

отправку пока оставим в покое я так понял.

сейчас клиента доделаю.
PM WWW   Вверх
mes
Дата 28.10.2010, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  08:51 Найти цитируемый пост)
т.е. команды для клиента и сервера разные? не связанные между собой?

при простой модели ( точка <-> точка )  команды симметричны  т.е. что у одного для отправки у другого для приема..

Добавлено через 4 минуты и 10 секунд
Цитата(boostcoder @  28.10.2010,  09:58 Найти цитируемый пост)
Цитата(mes @  28.10.2010,  09:17 )
нам важны сейчас две его функции , отправки и приема сырых данных.. 

по приему данных все ок. в коде сервера, в строке 77, заголовок и тело прочитаны. можно диспетчеризировать.

имелось ввиду что не важен сам процесс отправки, и другие функции такие как подключение..

наш rpc_sender с ресивером могут работать в том числе и без сетевого клиента ( если взаимодействие не через сеть)..
но это опять забегание вперед, для того чтоб немножко снизить туманость на пути к цели smile

Добавлено через 14 минут и 42 секунды
Цитата(boostcoder @  28.10.2010,  09:58 Найти цитируемый пост)
 строке 77, заголовок и тело прочитаны. можно диспетчеризировать.

да, только, чтоб можно было диспатчеризовать кому угодно, и развязать нам руки, вместо  _impl поставить  делегата 
smile


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



код клиента.
только не связал rpc_sender и rpc_receiver, ибо не уверен что все понял..
Код


#include "header.hpp"

/***************************************************************************/

struct rpc_sender {

   std::function<void()> raw_send;
   
   rpc_sender(constants::header_buffer& h, constants::body_buffer& b)
      :_header(h),_body(b)
   {}
   
   template<typename T>
   void send(const T& o) {
      serializer(_header, _body, o);
      raw_send();
   }

private:
   constants::header_buffer& _header;
   constants::body_buffer& _body;
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver(constants::header_buffer& h, constants::body_buffer& b)
      :_header(h),_body(b)
   {}

   void dispatch() {
      std::cout << _header.begin() << std::endl;
   }

private:
   constants::header_buffer& _header;
   constants::body_buffer& _body;
};

/***************************************************************************/

struct client {
   client(boost::asio::io_service& ios, const char* ip, boost::uint16_t port)
      :_socket(ios),
      _idx(0)
   {
      boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
      _socket.connect(endpoint);
      std::cout << "client: connected to server" << std::endl;
      /**  */
      start_read();
   }

   ~client() {
      _socket.close();
      std::cout << "destructing client" << std::endl;
   }

   void start_read() {
      boost::asio::async_read(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&client::header_read_handler, this, boost::asio::placeholders::error)
      );
   }

   void raw_send() {
      boost::asio::async_write(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&client::header_write_handler, this, boost::asio::placeholders::error)
      );
   }

   void header_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** заголовок прочитан */
         boost::asio::async_read(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&client::body_read_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "client: error read header" << std::endl;
      }
   }

   void body_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** тело прочитано */
         start_read();
      } else {
      }
   }

   void header_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** заголовок отправлен */
         boost::asio::async_write(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&client::body_write_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "client: error on writing to server" << std::endl;
      }
   }

   void body_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** тело отправлено */
      } else {
         std::cout << "client: error on writing to server" << std::endl;
      }
   }

   constants::header_buffer _header;
   constants::body_buffer _body;

private:
   boost::asio::ip::tcp::socket _socket;
   int _idx;
};

/***************************************************************************/

int main() {
   try {
      boost::asio::io_service ios;
      client client(ios, host, port);
      ios.run();
   } catch (const std::exception& e) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
}

/***************************************************************************/



PM WWW   Вверх
mes
Дата 28.10.2010, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  10:59 Найти цитируемый пост)
  std::function<void(header&, body&)> raw_send;


Добавлено через 1 минуту и 29 секунд
Цитата(boostcoder @  28.10.2010,  10:59 Найти цитируемый пост)
rpc_receiver {
   rpc_receiver(constants::header_buffer& h, constants::body_buffer& b)
      :_header(h),_body(b)

нет.. 

Код

struct rpc_receiver {
   
   void dispatch(header&, body&) {
      std::cout << _header.begin() << std::endl;
   }



Добавлено через 3 минуты и 11 секунд
выкидываем пока клиента... а то Вас так прям и тянет в сторону ...

Добавлено через 4 минуты и 52 секунды
пишем только сендер и ресивер.. связываем выход сендера, со входом ресивера.. 
при отправке пользователем тпизированного сообщения, ресивер должен распечать его в сыром виде.. 
smile

Добавлено через 5 минут и 54 секунды
т.е связаны должны быть  raw_send и dispatch 
smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



вот.
Код


#include "header.hpp"

/***************************************************************************/

struct rpc_sender {

   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;
   
   rpc_sender() {}
   
   template<typename T>
   void send(const T& o) {
      raw_send(...); /** объекты заголовка и тела должны быть локальными? */
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}

   void dispatch(constants::header_buffer& h, constants::body_buffer& и) {
      std::cout << р.begin() << std::endl;
   }
};

/***************************************************************************/

struct client {
   client(boost::asio::io_service& ios, const char* ip, boost::uint16_t port)
      :_socket(ios),
      _idx(0)
   {
      boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
      _socket.connect(endpoint);
      std::cout << "client: connected to server" << std::endl;
      /**  */
      start_read();
   }

   ~client() {
      _socket.close();
      std::cout << "destructing client" << std::endl;
   }

   void start_read() {
      boost::asio::async_read(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&client::header_read_handler, this, boost::asio::placeholders::error)
      );
   }

   void raw_send() {
      boost::asio::async_write(_socket,
         boost::asio::buffer(_header, _header.size()),
         boost::bind(&client::header_write_handler, this, boost::asio::placeholders::error)
      );
   }

   void header_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** заголовок прочитан */
         boost::asio::async_read(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&client::body_read_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "client: error read header" << std::endl;
      }
   }

   void body_read_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** тело прочитано */
         start_read();
      } else {
      }
   }

   void header_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** заголовок отправлен */
         boost::asio::async_write(_socket,
            boost::asio::buffer(_body, header_coders::decode_header(_header).body_length),
            boost::bind(&client::body_write_handler, this, boost::asio::placeholders::error)
         );
      } else {
         std::cout << "client: error on writing to server" << std::endl;
      }
   }

   void body_write_handler(const boost::system::error_code& e) {
      if ( !e ) {
         /** тело отправлено */
      } else {
         std::cout << "client: error on writing to server" << std::endl;
      }
   }

   constants::header_buffer _header;
   constants::body_buffer _body;

private:
   boost::asio::ip::tcp::socket _socket;
   int _idx;
};

/***************************************************************************/

int main() {
   try {
      boost::asio::io_service ios;
      client client(ios, host, port);
      ios.run();
   } catch (const std::exception& e) {
      std::cout << "(exception): " << e.what() << std::endl;
   }
}

/***************************************************************************/


PM WWW   Вверх
mes
Дата 28.10.2010, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  11:09 Найти цитируемый пост)
/** объекты заголовка и тела должны быть локальными? */

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

Добавлено через 1 минуту и 45 секунд
а посмотрел на клиент.. вы не то связали..  raw_send  не привязывается к клиенту ..

Добавлено через 2 минуты и 17 секунд
т.е. не привязывается как хэндлер записи... 


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 12:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  12:02 Найти цитируемый пост)
выкидываем пока клиента... а то Вас так прям и тянет в сторону ...

Добавлено через 4 минуты и 52 секунды
пишем только сендер и ресивер.. связываем выход сендера, со входом ресивера.. 
при отправке пользователем тпизированного сообщения, ресивер должен распечать его в сыром виде.. 

т.е. код клиента выкидываем, и в main() связываем только два объекта sender и receiver ?
PM WWW   Вверх
mes
Дата 28.10.2010, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  11:16 Найти цитируемый пост)
т.е. код клиента выкидываем, и в main() связываем только два объекта sender и receiver ? 

сейчас да.. чтоб Вы поняли как клиент подключать smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



так?
Код

/***************************************************************************/

struct rpc_sender {

   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;

   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
      raw_send(_header, _body);
   }
private:
   constants::header_buffer _header;
   constants::body_buffer _body;
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}

   void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      std::cout << h.begin() << std::endl;
   }
};

/***************************************************************************/

int main() {
   rpc_sender sender;
   rpc_receiver receiver;

   sender.raw_send = boost::bind(&rpc_receiver::dispatch, &receiver);
}

/***************************************************************************/



Это сообщение отредактировал(а) boostcoder - 28.10.2010, 12:34
PM WWW   Вверх
mes
Дата 28.10.2010, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



вобще то так :
Код

struct rpc_sender {
   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;
   rpc_sender() {}

   template<typename T>
     void send(const T& o) {

        constants::header_buffer _header;
        constants::body_buffer    _body;
       
        serializer(_header, _body, o);      
        raw_send(_header, _body);
    }
};




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



хорошо.
что дальше?
PM WWW   Вверх
mes
Дата 28.10.2010, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



так?
Код

/***************************************************************************/

struct i_invoker {
   virtual void dispatch(constants::header_buffer&, constants::body_buffer&) = 0;
};
typedef std::shared_ptr<i_invoker> i_invoker_ptr;

template<typename T, typename C>
struct invoker: i_invoker {
   typedef void(C::*handler_t)(T&);

   invoker(C* p, handler_t h):_this(p),_handler(h) {}

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      T data;
      deserializer(data, h, b);
      (*_this.*_handler)(data);
   }

private:
   C* _this;
   handler_t _handler;
};

/***************************************************************************/

struct rpc_sender {
   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;
   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
      constants::header_buffer _header;
      constants::body_buffer _body;

      serializer(_header, _body, o);
      raw_send(_header, _body);
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {
      /** init */
   }

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

/***************************************************************************/

int main() {
   rpc_sender sender;
   rpc_receiver receiver;

   sender.raw_send = boost::bind(&rpc_receiver::dispatch, &receiver);
}

/***************************************************************************/


PM WWW   Вверх
mes
Дата 28.10.2010, 13:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



опять не совсем.. слишком рано для предположения о передачи типизированного сообщения ресиверу... ресивер это чать rpc, a сообщения должны обрабатываться в пользовательской части ..
smile

Добавлено через 2 минуты и 45 секунд
Цитата(boostcoder @  28.10.2010,  12:02 Найти цитируемый пост)
struct rpc_receiver {
   rpc_receiver() {
      /** init */
   }
   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }

Код

struct rpc_receiver {
   rpc_receiver() {
      /** не нужен : init */
   }
    /* стереть : virtual */ 
      void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }



Это сообщение отредактировал(а) mes - 28.10.2010, 13:11


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



значит так:
Код

/***************************************************************************/

struct i_invoker {
   virtual void dispatch(constants::header_buffer&, constants::body_buffer&) = 0;
};
typedef std::shared_ptr<i_invoker> i_invoker_ptr;

template<typename T, typename C>
struct invoker: i_invoker {
   typedef void(C::*handler_t)(T&);

   invoker(C* p, handler_t h):_this(p),_handler(h) {}

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      T data;
      deserializer(data, h, b);
      (*_this.*_handler)(data);
   }

private:
   C* _this;
   handler_t _handler;
};

/***************************************************************************/

struct rpc_sender {
   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;
   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
      constants::header_buffer _header;
      constants::body_buffer _body;

      serializer(_header, _body, o);
      raw_send(_header, _body);
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}

   void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

/***************************************************************************/

int main() {
   rpc_sender sender;
   rpc_receiver receiver;

   sender.raw_send = boost::bind(&rpc_receiver::dispatch, &receiver);
}

/***************************************************************************/



Цитата(mes @  28.10.2010,  13:10 Найти цитируемый пост)
слишком рано для предположения о передачи типизированного сообщения ресиверу... ресивер это чать rpc, a сообщения должны обрабатываться в пользовательской части ..

не понимаю к чему это сказано....
PM WWW   Вверх
mes
Дата 28.10.2010, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  12:02 Найти цитируемый пост)

template<typename T, typename C>
struct invoker: i_invoker {
   typedef std::function< void()(T&)> func_t; // пока такой делегат

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      T data;
      deserializer(data, h, b);
      m_func (data);
   }
...

};




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110




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

PM WWW   Вверх
mes
Дата 28.10.2010, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  12:18 Найти цитируемый пост)
может оказаться так, как уже было... что мы четыре страницы не могли понять друг-друга..

сейчас так и происходит..поэтому я частями и даю.. smile
ничего скоро уже должно подойти к цели 
smile

Добавлено через 1 минуту и 29 секунд
добавляем к ресиверу функцию (шаблонную) для регистрации обработчика (сейчас лямбда функции)


Это сообщение отредактировал(а) mes - 28.10.2010, 13:22


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ага.
Код

/***************************************************************************/

struct i_invoker {
   virtual void dispatch(constants::header_buffer&, constants::body_buffer&) = 0;
};
typedef std::shared_ptr<i_invoker> i_invoker_ptr;

template<typename T>
struct invoker: i_invoker {
   typedef std::function<void(T&)> func_t;

   invoker(func_t& f):m_func(f){}

   virtual void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      T data;
      deserializer(data, h, b);
      m_func(data);
   }
   func_t m_func;
};

/***************************************************************************/

struct rpc_sender {
   std::function<void(constants::header_buffer&, constants::body_buffer&)> raw_send;
   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
      constants::header_buffer _header;
      constants::body_buffer _body;

      serializer(_header, _body, o);
      raw_send(_header, _body);
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}

   void dispatch(constants::header_buffer& h, constants::body_buffer& b) {
      int id = header_coders::decode_header(h).id;
      _map[id]->dispatch(h, b);
   }

   template<typename T>
   void reg(typename i_invoker<T>::func_t& f) {
      _map[T::id] = i_invoker_ptr(new invoker<T>(f));
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

/***************************************************************************/

int main() {
   rpc_sender sender;
   rpc_receiver receiver;

   sender.raw_send = boost::bind(&rpc_receiver::dispatch, &receiver);
}

/***************************************************************************/



Добавлено @ 13:38
код не компилил. так что использовать как псевдокод.

Это сообщение отредактировал(а) boostcoder - 28.10.2010, 13:38
PM WWW   Вверх
mes
Дата 28.10.2010, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



как сделаете заводите два сообщения query и result
и вот тестовый пример :
Код


int main() {
// ....................................................

   rpc_sender client_sender;
   rpc_receiver client_receiver;
  
    client_recevier.set_handler<result> ([](result const&)
    {
         std::cout << "result,  hurra! " << std::endl;
    })
// ....................................................

   rpc_sender  server_sender;
   rpc_receiver server_receiver;

    client_recevier.set_handler<query> ([&client_sender](query const&)
    {
         std::cout << "query.. "
         client_sender.send (result());
    })
// ....................................................

   client_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &server_receiver);
   server_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &client_receiver);

// ....................................................

    client_sender.send (query());

// ....................................................
}


set_handler это reg.


Это сообщение отредактировал(а) mes - 28.10.2010, 13:40


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(boostcoder @  28.10.2010,  13:37 Найти цитируемый пост)
_map[T::id] = i_invoker_ptr(new invoker<T>(f));

тут непонятно что использовать как ключ.. или же эту часть должен сгенерировать кодогенератор?

Добавлено через 1 минуту и 59 секунд
Цитата(mes @  28.10.2010,  13:38 Найти цитируемый пост)
   client_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &server_receiver);
   server_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &client_receiver);

 smile  smile 
PM WWW   Вверх
mes
Дата 28.10.2010, 13:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  12:40 Найти цитируемый пост)
тут непонятно что использовать как ключ.. или же эту часть должен сгенерировать кодогенератор? 

T::id .. не понял вопроса.. 
кодогенератора у нас нет пока (мы догаваривались же).. все вручную smile

Добавлено @ 13:43
Цитата(boostcoder @  28.10.2010,  12:40 Найти цитируемый пост)
    


Цитата(boostcoder @  28.10.2010,  12:40 Найти цитируемый пост)
   client_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &server_receiver);
   server_sender.raw_send = boost::bind(&rpc_receiver::dispatch, &client_receiver);
..  smile 
     

что то не так ? 
 smile 

Это сообщение отредактировал(а) mes - 28.10.2010, 13:44


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  13:42 Найти цитируемый пост)
что то не так ? 

все так.
еще одно непонимание разрешилось)
PM WWW   Вверх
mes
Дата 28.10.2010, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  12:45 Найти цитируемый пост)
все так.
еще одно непонимание разрешилось) 

отлично smile

Добавлено @ 13:47
как тестовый пример заработает, считайте что главное сделали.
smile

Добавлено через 10 минут и 36 секунд
как закончите выкладывайте этот примерчик на онлайн-компиляторе..
чтоб можно было визуально оценить куда дальше рельсы класть smile


Это сообщение отредактировал(а) mes - 28.10.2010, 13:49


--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



чего то долговато.. там вроде ж у Вас все готово.. или опять чего то лишнее прикручиваете ?
 smile 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



smile 
вот: http://liveworkspace.org/code/a372e0ad39ad...d988c17158dc121
что-то компилятор ругается..

Добавлено через 13 минут и 9 секунд
не вижу ошибки.. вполне законное связывание..
PM WWW   Вверх
mes
Дата 28.10.2010, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  13:45 Найти цитируемый пост)
не вижу ошибки.. вполне законное связывание.. 

это моя ошибка, в связывании забыты плейсхолдеры smile

Добавлено через 2 минуты и 19 секунд
терь не хватает кода сериализации, чтоб увидеть результат.. 
smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ы)
http://liveworkspace.org/code/3c9e2679054c...56b18c4669b1ff3

Добавлено через 18 секунд
осталось понять почему нет вывода..

Добавлено через 2 минуты и 4 секунды
Цитата(mes @  28.10.2010,  15:03 Найти цитируемый пост)
терь не хватает кода сериализации, чтоб увидеть результат..

это спешка.. сейчас сделаю..
PM WWW   Вверх
boostcoder
Дата 28.10.2010, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



вот: http://liveworkspace.org/code/e41ca2a8c07f...49cabd172c9e0ab

но есть один вопрос не позволяющий завершить код: как быть с meta_dir ? это индикатор направления пакета.

Добавлено через 44 секунды
убрать пока его?

PM WWW   Вверх
mes
Дата 28.10.2010, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  14:40 Найти цитируемый пост)
но есть один вопрос не позволяющий завершить код: как быть с meta_dir ? это индикатор направления пакета.

ну а откуда он взялся ?  smile   в плане работ его не было smile  smile 
 smile

Добавлено через 19 секунд
сейчас код гляну smile



--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



чего то вы там  хидерами и бодями нахимичили.. 


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  15:57 Найти цитируемый пост)
ну а откуда он взялся ?     в плане работ его не было    

значит не будет  smile 
еще с сериализацией разберусь...
PM WWW   Вверх
mes
Дата 28.10.2010, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  15:36 Найти цитируемый пост)
еще с сериализацией разберусь... 

я думаю сейчас пора убраться от лишних зависимостей реализации.. и объединить хидер с бодом в одном пакете.. 
smile соответсвенно все функции принимавшие эти два параметра , терь будут принимать один .. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  16:57 Найти цитируемый пост)
хидер с бодом в одном пакете.. 

затайпдефить новый тип?

Добавлено через 7 минут и 48 секунд
вот: http://liveworkspace.org/code/ae95e786e658...dbed5ee67d368e5
осталось понять почему не вызывается invoker::dispatch() ..

Добавлено через 12 минут и 2 секунды
карта почему-то пустая. хотя зарегано по одному обработчику..
PM WWW   Вверх
boostcoder
Дата 28.10.2010, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



с этим разобрался: http://liveworkspace.org/code/2da9190f091a...28913d37ff318ba
еще ответ на query не срабатывает smile

Добавлено через 2 минуты и 47 секунд
вот. и с этим разобрался: http://liveworkspace.org/code/43a5b1c35f66...9868a3941c5a04b
гляньте плиз, я ничего не напутал?
можно считать этот код опорной точкой для продолжения?

Добавлено через 9 минут и 55 секунд
и еще: http://liveworkspace.org/code/f936ac96af0b...80ef89ab01d68e0
PM WWW   Вверх
mes
Дата 28.10.2010, 17:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  16:20 Найти цитируемый пост)
гляньте плиз, я ничего не напутал?

на вид пока все ок )

Цитата(boostcoder @  28.10.2010,  16:20 Найти цитируемый пост)
можно считать этот код опорной точкой для продолжения? 

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

заводим структуру 
Код

struct rpc_packet
{
       size_t id;
// пока в ней ничего большего.. 
};

убираем весь код сериализации в сторону, и вмето хидера_с_бодей ставим нашу структуру..




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  17:36 Найти цитируемый пост)
нужно избавиться от лишних. зависимостей..

каких именно, и каким образом?

Цитата(mes @  28.10.2010,  17:36 Найти цитируемый пост)
пока эту часть консервируем и делаем от нее ответление..

т.е. на основе этого кода? или писать с нуля?

Цитата(mes @  28.10.2010,  17:36 Найти цитируемый пост)
убираем весь код сериализации в сторону, и вмето хидера_с_бодей ставим нашу структуру..

т.е. эту структуру вписать в другой дополнительный хидер?
PM WWW   Вверх
mes
Дата 28.10.2010, 18:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  17:11 Найти цитируемый пост)
каких именно, и каким образом?

так же как от нет_клиента избавились smile


Цитата(boostcoder @  28.10.2010,  17:11 Найти цитируемый пост)
т.е. на основе этого кода? или писать с нуля?

зачем с нуля ? сейчас код весь нужный, только неправильно расфасован.. 
создаете новый файл, перекидываете туда все кроме сериализации и меняете параметры функций на rpc_packet.. 


Цитата(boostcoder @  28.10.2010,  17:11 Найти цитируемый пост)
т.е. эту структуру вписать в другой дополнительный хидер? 

нет, грубо говоря сериализацию вынести в другой хидер... 
smile

Добавлено через 33 секунды
сейчас подождите.. я сам сделаю .. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  18:16 Найти цитируемый пост)
сейчас подождите.. я сам сделаю .. 

ы smile 
PM WWW   Вверх
mes
Дата 28.10.2010, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250





--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  18:27 Найти цитируемый пост)
вот что я просил

ага. ок.
что теперь?

Добавлено через 5 минут и 6 секунд
кстати, а зачем нам rpc_packet ?
или это новый тип взамен хедера и бади?

Добавлено через 6 минут и 29 секунд
по идее - да.
в нем будут локальные буфера и сериализация/десериализация. smile
PM WWW   Вверх
mes
Дата 28.10.2010, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  17:32 Найти цитируемый пост)
что теперь? 

терь надо определиться с пакетом.. какое взаимодействие он должен поддерживать.. 




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



так как в планах у нас есть динамическое создание обработчиков(а по мне, так обработчики должны быть методами класса), в нем должен быть идентификатор класса обработчика. так же, можно реализовать передачу служебных сообщений таких как например, исключения smile 
PM WWW   Вверх
mes
Дата 28.10.2010, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



минутку не торопитесь... давайте приведем вначале к стартовой точке.. 
smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(boostcoder @  28.10.2010,  18:44 Найти цитируемый пост)
в нем должен быть идентификатор класса обработчика

т.е. после десериализации пакета, определяем ID класса в котором находится обработчик для команды этого типа. просматриваем карту на предмет наличия этого класса. если есть - берем диспетчера этого класса и передаем ему пакет. если нет - бросить исключение клиенту обратно.

Добавлено через 33 секунды
Цитата(mes @  28.10.2010,  18:46 Найти цитируемый пост)
минутку не торопитесь

мысли вслух...
PM WWW   Вверх
mes
Дата 28.10.2010, 18:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

Добавлено через 28 секунд
вы пока с сериализацией мучайтесь, а я пока про ресивер подумаю ))



--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



и еще invoker нужно  занестить в ресивер.. 
и разгрузить вызов функции инвокера через внешнюю шаблонную функцию.. 




--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 19:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  19:06 Найти цитируемый пост)
и еще invoker нужно  занестить в ресивер.. 
и разгрузить вызов функции инвокера через внешнюю шаблонную функцию.. 

эм.. поясните ;)
PM WWW   Вверх
mes
Дата 28.10.2010, 19:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  18:16 Найти цитируемый пост)
 занестить

в принципе пока не обязательно.. имелось ввиду определить его  в пространстве ресивера..
Код

struct receiver { struct invoker; };



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 19:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mes @  28.10.2010,  19:37 Найти цитируемый пост)
в принципе пока не обязательно.. имелось ввиду определить его  в пространстве ресивера..

ок. делаю.
PM WWW   Вверх
mes
Дата 28.10.2010, 19:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  18:16 Найти цитируемый пост)
и разгрузить вызов функции инвокера через внешнюю шаблонную функцию.

сделать две шаблонные функции
Код

packet to_paket(T const& );
T  from_packet (packet const&);

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

Код

struct sender { .. void send (const T& msg) { raw_send (to_packet<T>(msg)); };
struct invoker { ..void dispatch (..) { func( from_packet<T>(pack)); };


Добавлено через 1 минуту и 50 секунд
Цитата(mes @  28.10.2010,  18:43 Найти цитируемый пост)
to_paket

названия не очень удачные.. но если ничего лучше не придет в голову, можно пока так оставить smile


Это сообщение отредактировал(а) mes - 28.10.2010, 19:44


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ок. и это сделаю.

Добавлено через 12 минут и 55 секунд
это:
Цитата(mes @  28.10.2010,  19:37 Найти цитируемый пост)
struct receiver { struct invoker; };

и это:
Цитата(mes @  28.10.2010,  19:43 Найти цитируемый пост)
struct sender { .. void send (const T& msg) { raw_send (to_packet<T>(msg)); };
struct invoker { ..void dispatch (..) { func( from_packet<T>(pack)); };

так как делать?
PM WWW   Вверх
mes
Дата 28.10.2010, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  18:53 Найти цитируемый пост)
так как делать? 

вобще то одно другому не мешает..

покажите что у Вас сейчас 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



PM WWW   Вверх
mes
Дата 28.10.2010, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  19:23 Найти цитируемый пост)
пока это: http://liveworkspace.org/code/65e326b96f50...75cf88e243f2c9b 

я думал вы хоть пакет уже добавили..  smile

Добавлено через 1 минуту и 27 секунд
кстати имхо подход не очень верный.. Вы пытаетесь к сериализации добавить пакет... а нужно с другой строны подходить, к пакету добавлять сериализацию smile
так будет легче и яснее )


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



так я не был уверен что все правильно понял. выше написал.
сейчас все будет.

PM WWW   Вверх
mes
Дата 28.10.2010, 20:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



вот вам протипы пакета и пакетных функций..
Код

struct rpc_packet {
  size_t id;
};

template<class T>
rpc_packet rpc_pack (T const&)
{
      rpc_packet pack; 
      pack.id = T::meta_id;
      return pack;
}
template<class T>
T rpc_unpack (rpc_packet const&)
{
   return T();
}

вся сериализация должна быть в них ..

Добавлено @ 20:55
тогда сендер будет выглядить так :
Код

struct rpc_sender {
   std::function<void(rpc_packet const&)> raw_send;
   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
        raw_send(rpc_pack<T>(o));
   }
};

и является теперь не зависимым от устройства рпц_библиотеки 

с остальным будет также.. 
smile

это я Вам опять немножко из будущего вытащил 
smile

Это сообщение отредактировал(а) mes - 28.10.2010, 21:02


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



минутку...ща все будет..

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


Добавлено через 14 минут и 31 секунду
Цитата(mes @  28.10.2010,  20:52 Найти цитируемый пост)
struct rpc_packet {
  size_t id;
};

в ней же должны быть и хедер и бади. так?
PM WWW   Вверх
mes
Дата 28.10.2010, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  19:58 Найти цитируемый пост)
в ней же должны быть и хедер и бади. так? 

да, если нужны.. и как нужны )

Добавлено через 2 минуты и 18 секунд
вот я подправил остальное : http://liveworkspace.org/code/baa9b08e0051...92bdb22c903daba

Это сообщение отредактировал(а) mes - 28.10.2010, 21:17


--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 21:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



после можно будет  написать класс rpc_receiver2, с инвокерами которые будут вызывать не function, а метод класса..
объект класса будет хранить ресивер..
P.S.старый ресивер не выкидывайте.. 







--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



эврика!
http://liveworkspace.org/code/661062d84fc5...cbe28b7e5403890

сейчас еще пересмотрю код. кодировщик/декодировщик заголовка пакета нужно куда-то всунуть.

Добавлено @ 22:02
гляньте пожалуйста, может еще что-то найдете ;)

Добавлено через 9 минут и 28 секунд
навел порядок: http://liveworkspace.org/code/e1be046e609b...44396051e4c81b6

Добавлено через 12 минут и 32 секунды
теперь, как я предполагал, rpc_packet::id это идентификатор класса с его обработчиком?


Это сообщение отредактировал(а) boostcoder - 28.10.2010, 22:02
PM WWW   Вверх
mes
Дата 28.10.2010, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  21:01 Найти цитируемый пост)
гляньте пожалуйста, может еще что-то найдете ;)

Код

struct rpc_packet {
   size_t id;
   constants::header_buffer header;


а для чего пакету хидер как буффер ?!  
сделайте лучше возможность сериализации пакета..

Добавлено через 3 минуты и 14 секунд
а paket::body нам тоже не нужен статического размера.. и можно заменить на строку/вектор..

Добавлено через 12 минут и 35 секунд
Код

   void dispatch(const types::rpc_packet& pack) {
...
      int id = types::decode_header(pack.header).id;
      _map[id]->dispatch(pack);
   }


Код

  void dispatch(const types::rpc_packet& pack) {      
        
      _map[id]->dispatch(pack.header.id); // либо pack.id
   //  и вместо _map[] нужно _map.find()..
   }


Это сообщение отредактировал(а) mes - 28.10.2010, 22:41


--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 22:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



как это подправите, можно считать полученное отправной точкой.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 28.10.2010, 22:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ок. сейчас..
PM WWW   Вверх
mes
Дата 28.10.2010, 22:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  21:01 Найти цитируемый пост)
сейчас еще пересмотрю код. кодировщик/декодировщик заголовка пакета нужно куда-то всунуть

это уровень сети... здесь нам не нужно..

Добавлено @ 23:00
вобщем  нужно примерно так :
Код

struct packet {
    size_t id;
    std::string raw_data;   // std::vector 
};


все остальное (из constants) в мусорку 
smile



Это сообщение отредактировал(а) mes - 28.10.2010, 23:01


--------------------
PM MAIL WWW   Вверх
mes
Дата 28.10.2010, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



не дождался , сам подправил :
http://liveworkspace.org/code/aa539e62ca1c...0017fe1a180288b
smile

Добавлено @ 23:46
пусть будет здесь, для надежности.. 

Код

#include <iostream>
#include <functional>
#include <array>
#include <memory>
#include <map>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>


/***************************************************************************/
   struct rpc_packet {
      size_t id;
      std::string raw_data;  
   };

   template<typename T>
   rpc_packet rpc_pack(T const& o) {
      rpc_packet pack;
      pack.id = T::meta_id;
      std::ostringstream os;
      boost::archive::text_oarchive(os) << o;
      pack.raw_data = os.str();
   
      return pack;
   }
   template<typename T>
   T rpc_unpack(rpc_packet const& pack) {
      T data;
      std::istringstream is( pack.raw_data );
      boost::archive::text_iarchive(is) >> data;
      return data;
   }

/***************************************************************************/

struct rpc_sender {
   std::function<void( rpc_packet const&)> raw_send;
   rpc_sender() {}

   template<typename T>
   void send(const T& o) {
      raw_send(rpc_pack<T>(o));
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}
   
   struct i_invoker {
      virtual void dispatch(rpc_packet const &) = 0;
   };
   typedef std::shared_ptr<i_invoker> i_invoker_ptr;

   template<typename T>
   struct invoker;
   
   void dispatch(rpc_packet const& pack) {
       
      auto it  = _map.find(pack.id);
      if ( it != _map.end() && it->second )
         it->second->dispatch(pack);
   }

   template<typename T>
   void set_handler(typename invoker<T>::func_t f) {
      _map[T::meta_id] = i_invoker_ptr(new invoker<T>(f));
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

template<typename T>
struct rpc_receiver::invoker: i_invoker {
   typedef std::function<void(const T&)> func_t;

   invoker(func_t& f):m_func(f){}

   virtual void dispatch(rpc_packet const& pack) {

      m_func(rpc_unpack<T>(pack));
   }
   
private:
   func_t m_func;
};

/***************************************************************************/

struct query {
   query() {}
   query(const std::string& s, int c):message(s),code(c) {}

   enum { meta_id = 0 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

struct result {
   result() {}
   result(const std::string& s, int c):message(s),code(c) {}
   
   enum { meta_id = 1 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

/***************************************************************************/

int main() {
   /** client */
   rpc_sender client_sender;
   rpc_receiver client_receiver;
   
   client_receiver.set_handler<result>(
      [](const result& r) {
         std::cout
         << "from server:" << std::endl
         << "   msg : " << r.message << std::endl
         << "   code: " << r.code << std::endl;
      }
   );
   
   /** server */
   rpc_sender server_sender;
   rpc_receiver server_receiver;

   server_receiver.set_handler<query>(
      [&server_sender](const query& q) {
         std::cout
         << "from client:" << std::endl
         << "   msg : " << q.message << std::endl
         << "   code: " << q.code << std::endl;
         server_sender.send(result("Ok", 1));
      }
   );

   /**  */
   client_sender.raw_send = std::bind(&rpc_receiver::dispatch, &server_receiver, std::placeholders::_1);
   server_sender.raw_send = std::bind(&rpc_receiver::dispatch, &client_receiver, std::placeholders::_1);

   /**  */
   client_sender.send(query("query", 3));
}

/***************************************************************************/



Это сообщение отредактировал(а) mes - 28.10.2010, 23:46


--------------------
PM MAIL WWW   Вверх
mes
Дата 29.10.2010, 00:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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


Это сообщение отредактировал(а) mes - 29.10.2010, 00:25


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 29.10.2010, 00:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



если я ничего не напутал, то здесь ошибочка.
в rpc_pack вы не пакуете идентификатор. но при распаковке пакета, нам не известен его идентификатор, и в функции rpc_unpack вы его не распаковываете. или я опять что-то напутал?
PM WWW   Вверх
boostcoder
Дата 29.10.2010, 02:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



вот что у меня получилось:
Код

#include <iostream>
#include <functional>
#include <array>
#include <memory>
#include <map>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

/***************************************************************************/

namespace types {
   enum { header_length = 12 };
   static const char* format = "%02d%04d%06d";
   
   typedef std::string rpc_packet;
   
   size_t get_class_id(const rpc_packet& pack) {
      size_t id = 0, unused1, unused2;
      sscanf(pack.data(), format, &id, &unused1, &unused2);
      return id;
   }

   size_t get_meta_id(const rpc_packet& pack) {
      size_t id = 0, unused1, unused2;
      sscanf(pack.data(), format, &unused1, &id, &unused2);
      return id;
   }
   
   size_t get_body_len(const rpc_packet& pack) {
      size_t unused1, unused2, len = 0;
      sscanf(pack.data(), format, &unused1, &unused2, &len);
      return len;
   }

   template<typename T, typename C>
   std::string encode_header(const std::string& body) {
      std::string tmp(header_length, 0);
      sprintf(&tmp[0], format, C::class_id, T::meta_id, body.length());
      return tmp;
   }

   template<typename T, typename C>
   rpc_packet rpc_pack(const T& o) {
      std::ostringstream os;
      boost::archive::text_oarchive(os) << o;
      rpc_packet pack = encode_header<T, C>(os.str()) + os.str();
      std::cout << "rpc_pack::pack: " << pack << std::endl;
      return pack;
   }
   template<typename T>
   T rpc_unpack(const rpc_packet& pack) {
      T type;
      std::cout << "rpc_unpack::pack: " << pack << std::endl;
      std::istringstream is(std::string(pack.begin()+header_length, pack.end()));
      boost::archive::text_iarchive(is) >> type;
      return type;
   }
};

/***************************************************************************/

struct rpc_sender {
   std::function<void(const types::rpc_packet&)> raw_send;
   rpc_sender() {}

   template<typename T, typename C>
   void send(const T& o) {
      raw_send(types::rpc_pack<T, C>(o));
   }
};

/***************************************************************************/

struct rpc_receiver {
   rpc_receiver() {}
   
   struct i_invoker {
      virtual void dispatch(const types::rpc_packet&) = 0;
   };
   typedef std::shared_ptr<i_invoker> i_invoker_ptr;

   template<typename T>
   struct invoker;
   
   void dispatch(const types::rpc_packet& pack) {
      auto it = _map.find(types::get_meta_id(pack));
      if ( it == _map.end() || !it->second ) {
         throw std::runtime_error(" if 'rpc_receiver::dispatch()' bad ID");
      }
      it->second->dispatch(pack);
   }

   template<typename T>
   void set_handler(typename invoker<T>::func_t f) {
      _map[T::meta_id] = i_invoker_ptr(new invoker<T>(f));
   }

private:
   std::map<int, i_invoker_ptr> _map;
};

template<typename T>
struct rpc_receiver::invoker: i_invoker {
   typedef std::function<void(const T&)> func_t;

   invoker(func_t& f):m_func(f){}

   virtual void dispatch(const types::rpc_packet& pack) {
      m_func(types::rpc_unpack<T>(pack));
   }
   
private:
   func_t m_func;
};

/***************************************************************************/

struct query1 {
   query1() {}
   query1(const std::string& s, int c):message(s),code(c) {}

   enum { meta_id = 0 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

struct query2 {
   query2() {}
   query2(const std::string& s, int c):message(s),code(c) {}

   enum { meta_id = 0 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

struct result1 {
   result1() {}
   result1(const std::string& s, int c):message(s),code(c) {}
   
   enum { meta_id = 1 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

struct result2 {
   result2() {}
   result2(const std::string& s, int c):message(s),code(c) {}
   
   enum { meta_id = 1 };
   std::string message;
   int code;

private:
   friend class boost::serialization::access;
   template<typename archive_type>
   void serialize(archive_type& ar, const unsigned int) {
      ar & message
         & code;
   }
};

/***************************************************************************/

struct i_server_impl {
   enum { class_id = 0 };
   virtual void method(const query1&) = 0;
};

struct server_impl: i_server_impl {
   virtual void method(const query1& q) {
      std::cout << "impl1::method" << std::endl;
   }
};

struct i_client_impl {
   enum { class_id = 1 };
   virtual void method(const query2&) = 0;
};

struct client_impl: i_client_impl {
   virtual void method(const query2& q) {
      std::cout << "impl2::method" << std::endl;
   }
};

/***************************************************************************/

struct client {
   client() {
      receiver.set_handler<result1>(
         [](const result1& r) {
            std::cout
            << "from server:" << std::endl
            << "   msg : " << r.message << std::endl
            << "   code: " << r.code << std::endl;
         }
      );
   }

   rpc_sender sender;
   rpc_receiver receiver;
};

struct server {
   server() {
      receiver.set_handler<query1>(
         [&sender](const query1& q) {
            std::cout
            << "from client:" << std::endl
            << "   msg : " << q.message << std::endl
            << "   code: " << q.code << std::endl;
            sender.send<result1, client_impl>(result1("Ok", 1));
         }
      );
   }

   rpc_sender sender;
   rpc_receiver receiver;
};

/***************************************************************************/

int main() {
   client client;
   server server;

   client.sender.raw_send = std::bind(&rpc_receiver::dispatch, &server.receiver, std::placeholders::_1);
   server.sender.raw_send = std::bind(&rpc_receiver::dispatch, &client.receiver, std::placeholders::_1);

   client.sender.send<query1, server_impl>(query1("query1", 3));
}

/***************************************************************************/

http://liveworkspace.org/code/487c740c8d68...d30f827a3ef6efc

Это сообщение отредактировал(а) boostcoder - 29.10.2010, 03:11
PM WWW   Вверх
boostcoder
Дата 29.10.2010, 03:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

с утра уже..
PM WWW   Вверх
boostcoder
Дата 29.10.2010, 03:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



вот: http://liveworkspace.org/code/e86552b94c95...464261d3bd7d8cf
с обработчиками в виде классов.
вот только в данный момент нет возможности из обработчика сделать вызов...

Добавлено через 2 минуты и 17 секунд
нужно утвердить код, и вынести его в отдельный хидер, а то уже прокручивать палец болит)
PM WWW   Вверх
mes
Дата 29.10.2010, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  28.10.2010,  23:44 Найти цитируемый пост)
в rpc_pack вы не пакуете идентификатор. но при распаковке пакета, нам не известен его идентификатор, и в функции rpc_unpack вы его не распаковываете. или я опять что-то напутал? 

21я строчка в моем последнем наброске smile
а в unpack нам не нужен идентификатор, у нас там уже известен тип smile


Это сообщение отредактировал(а) mes - 29.10.2010, 08:57


--------------------
PM MAIL WWW   Вверх
mes
Дата 29.10.2010, 09:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  29.10.2010,  01:50 Найти цитируемый пост)
static const char* format = "%02d%04d%06d";

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

Добавлено @ 09:04
Цитата(boostcoder @  29.10.2010,  02:10 Найти цитируемый пост)
мне кажется логичным, создавать классы-обработчики по запросу, как я уже писал.

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

Добавлено @ 09:07
Код

    throw std::runtime_error(" if 'rpc_receiver::dispatch()' bad ID");

bad_ID будет при проверке среди возможных ид_пакетов.. А так это всего лишь не зарегистрированный handler smile

Добавлено @ 09:11
Цитата(boostcoder @  29.10.2010,  02:47 Найти цитируемый пост)
с обработчиками в виде классов.

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

Добавлено @ 09:14
Цитата(boostcoder @  29.10.2010,  02:47 Найти цитируемый пост)
нужно утвердить код, и вынести его в отдельный хидер,

утвержденый код (точнее его база) в сообщении предшествующее этому :
Цитата(mes @  28.10.2010,  23:00 Найти цитируемый пост)
теперь осталось сделать контроль пропуска сообщений, чтоб нельзя было отправить чужое сообщение, но уже сейчас можно запихнуть полученое в rpc_parts.h и на этой основе строить клиента..

smile

Это сообщение отредактировал(а) mes - 29.10.2010, 09:21


--------------------
PM MAIL WWW   Вверх
mes
Дата 29.10.2010, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Код

   client.sender.send<query1, server_impl>(query1("query1", 3));

 smile  smile  smile  smile 

Вы, как клиент, за сервер решили, каким образом ему обрабатывать свои сообщения ?!
 smile 





--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 29.10.2010, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



хорошо.
какая часть того кода остается неизменной, чтоб ее вынести в отдельный файл?
PM WWW   Вверх
mes
Дата 29.10.2010, 12:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  29.10.2010,  11:50 Найти цитируемый пост)
какая часть того кода остается неизменной, чтоб ее вынести в отдельный файл

не неизменной, а опорной.. все кроме маин.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 29.10.2010, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ок. закинул его в отдельный файл.
далее используем так:
Код

// http://liveworkspace.org/code/aa539e62ca1c9439d0017fe1a180288b
#include <rpc-rev1.hpp>

int main() {
   /** client */
   rpc_sender client_sender;
   rpc_receiver client_receiver;

   client_receiver.set_handler<result>(
      [](const result& r) {
         std::cout
         << "from server:" << std::endl
         << "   msg : " << r.message << std::endl
         << "   code: " << r.code << std::endl;
      }
   );

   /** server */
   rpc_sender server_sender;
   rpc_receiver server_receiver;
   server_receiver.set_handler<query>(
      [&server_sender](const query& q) {
         std::cout
         << "from client:" << std::endl
         << "   msg : " << q.message << std::endl
         << "   code: " << q.code << std::endl;
         server_sender.send(result("Ok", 1));
      }
   );
   /**  */
   client_sender.raw_send = std::bind(&rpc_receiver::dispatch, &server_receiver, std::placeholders::_1);
   server_sender.raw_send = std::bind(&rpc_receiver::dispatch, &client_receiver, std::placeholders::_1);
   /**  */
   client_sender.send(query("query", 3));
}

http://liveworkspace.org/code/93eb6d4eba45...fdc9ede71f34864

Это сообщение отредактировал(а) boostcoder - 29.10.2010, 13:15
PM WWW   Вверх
mes
Дата 29.10.2010, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  29.10.2010,  12:07 Найти цитируемый пост)
ок. закинул его в отдельный файл.

 smile 

терь в какую строну двигаемся ? готов выслушать пожелания smile



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 29.10.2010, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



smile 
я думаю что пора реализовать возможность создания обработчиков по запросу сторон. нет?

Добавлено через 4 минуты и 18 секунд
еще момент... пишу..

PM WWW   Вверх
mes
Дата 29.10.2010, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  29.10.2010,  12:12 Найти цитируемый пост)
я думаю что пора реализовать возможность создания обработчиков по запросу сторон. нет?

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



--------------------
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.3459 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.