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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> удаленный вызов. детали, реализация, архитектура, у темы новое название! 
:(
    Опции темы
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   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1288 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.