2014-03-06 82 views
1

我正在爲內部項目設計下一代框架體系結構。本質上有一個運行時系統,它可以爲應用程序提供一個API,以便在運行中加載/卸載。通用API發佈技術

在框架中生活一個自定義的「設備」庫這些設備的當前接口是非常通用的;認爲POSIX加載/卸載/讀/寫/等...框架的重要原則之一是,應用程序需要知道很少關於設備細節。

不幸的是,這個接口已經分解到應用程序開發人員最終在應用程序本身重寫通用函數的地方。

我在尋找建議,甚至是一個地方開始閱讀有關設計框架API這樣的。框架中的「設備」作者可以使用哪些工具來發布界面? 發佈界面的最佳途徑是什麼?

+0

你能具體談談什麼是缺乏在目前的體制,推動應用開發者放棄了嗎?你需要添加什麼樣的API函數,如果它們已經被加載/卸載/讀/寫,那麼會導致什麼問題? –

+0

目前的系統過於通用。我可能會創建一個可以進行信號處理的設備,另一個可以是電動機控制器。我可以用來發布的唯一接口方法是加載/卸載/讀取/寫入等等......我希望設備作者能夠發佈他們自己的該設備的自定義方法/函數,但允許應用程序不一定需要#包括任何額外的東西。他們應該能夠查詢已安裝設備的框架,然後獲取設備作者發佈的界面。 – Lother

+0

因此,說應用程序不包括任何額外的東西,可以找出並可能調用額外的功能,它將如何*決定是否/何時*調用它們,以及如何處理結果?未更改的應用程序將從某處(例如配置文件,鍵盤或UI小部件)讀取指定對這些功能的調用的輸入,還是應該編輯該應用程序以指定調用? –

回答

2

好的 - 一個建議 - 可能與你想要的有很大的不同,但是反饋會幫助你回到有用的東西。

對於同步「調用」,您希望您的應用程序模塊發送所需的驅動程序函數以及多個參數的指示,然後檢索一些結果。這可以通過具有第二個不同的讀取/寫入流的通用方式來實現,在該讀取/寫入流上傳輸函數和值的編碼。所以,說司機API包括:

string get_stuff(string x, int y, double d[]); 

這不是代碼 - 這是該框架/應用程序可打印/解析和潛在的使用來驗證數據的發送和相應消耗的文本。

應用程序模塊隨後將一個「調用」作爲函數標識符和輸入的流寫入驅動程序,然後讀取結果(假定應用程序模塊具有包含所需參數值的同名變量)。

driver_api << "get_stuff " << escape(x) << ' ' << y << " [" << d.size() << "] "; 
for (auto i = d.begin(); i != d.end(); ++i) 
    driver_api << ' ' << *i; 
driver_api << '\n'; 

std::getline(driver_api, result); 

這一點更多的工作(半小時?)來創建自定義數據流的包裝,可以包裹driver_api並插入上面的空格或其他分隔符/分隔符,支持集裝箱流和/或發送數據以二進制形式,讓你寫一個更清潔和/或以上,像更快的價值導向版本:

(driver_api << "get_stuff" << x << y << d) >> result; 

你也可以寫普通的C++函數來包裝上面的應用模塊調用:

string get_stuff(const std::string& x, int y, const std::vector<double>& d) 
{ 
    string result; 
    (driver_api_ << "get_stuff" << x << y << d) >> result; 
    return result; 
} 

在驅動程序方面,您會編寫匹配的反序列化例程以從流中恢復應用程序模塊指定的值。

對於特定的體系結構,您可能可以通過使用調試信息或ABI知識等方式讓庫更方便地調用函數,而上述只需要標準C++,並且可以編寫爲便攜式做endian值的二進制序列化)。編輯 - 二進制序列化的例子(現在只輸出/運行,但輸出沒有仔細檢查有效性/大多數東西固定寬度,但字符串NUL終止和容器前綴大小/不發送後續字段類型的信息但很容易地創建一個版本一樣):

#include <iostream> 
#include <vector> 

#include <winsock2.h> 
typedef signed char int8_t; 
typedef signed short int16_t; 
typedef signed int32_t; 
typedef unsigned char uint8_t; 
typedef unsigned short uint16_t; 
typedef unsigned uint32_t; 

class Binary_IOStream 
{ 
    public: 
    Binary_IOStream(std::istream& i, std::ostream& s) : i_(i), s_(s) { } 
    typedef Binary_IOStream This; 
    This& operator<<(int8_t x) { return write(x); } 
    This& operator<<(int16_t x) { return write(htons(x)); } 
    This& operator<<(int32_t x) { return write(htonl(x)); } 
    This& operator<<(uint8_t x) { return write(x); } 
    This& operator<<(uint16_t x) { return write(htons(x)); } 
    This& operator<<(uint32_t x) { return write(htonl(x)); } 
    This& operator<<(const std::string& s) 
     { s_.write(s.c_str(), s.size() + 1); // include NUL, but could size-prefix 
      return *this; } 
    This& operator<<(double x) { return write(x); } 

    template <typename T> 
    This& operator<<(const std::vector<T>& v) 
     { return write_range(v.begin(), v.end()); } 

    template <typename Iterator> 
    This& write_range(Iterator begin, Iterator end) 
    { 
     operator<<(std::distance(begin, end)); 
     while (begin != end) 
      operator<<(*begin++); 
     return *this; 
    } 

    private: 
    template <typename T> 
    This& write(const T& t) 
     { s_.write((const char*)&t, sizeof t); return *this; } 

    std::istream& i_; 
    std::ostream& s_; 
}; 

int main() 
{ 
    Binary_IOStream bs(std::cin, std::cout); 

    bs << ('A' << 24) + ('b' << 16) + ('c' << 8) + 'D'; 
    bs << "hello world!"; 
    std::vector<double> v; 
    v.push_back(3.14); 
    v.push_back(2.72); 
    bs << v; 
} 
+0

這正是我想到的想法。你能提出任何標準的編碼方式將呼叫編碼成流嗎?一些速度很快的東西(我不想要一堆xml包裝器),最好用原生格式的原始數據,但標準的我可以抓住一個c/C++庫。 – Lother

+0

我不知道其中的一個,但我將在一段代碼中進行編輯,以說明如何完成此操作。 –

+0

我想我完全理解你的建議。我現在可以編寫類似的東西,沒問題。如果有一個標準的方法來做到這一點會很好。我幾乎不能相信沒有。我認爲這是我搜索的下一步。我知道JSON做這樣的事情,但JSON速度不夠快(它編碼ascii字符串數據)我想要儘可能少的東西放入流中,並且非常快地構建/解構流,因爲編碼數據已經在本地格式。 – Lother