簡體   English   中英

具有泛型類型函數的動態庫[c ++]

[英]Dynamic Libraries with generic type functions [c++]

最后一天,我正在嘗試使用C ++做到這一點:

假設我有一個函數foo(arg1, arg2) ,一個客戶端和一台服務器。 arg1可以是任何類型, arg2可以是任何類型,而foo可以返回任何類型的數據。 函數foo始終有兩個參數。

我希望客戶端將此功能作為輸入(例如):

foo(arg1,arg2){

    if(arg1<arg2){
       return 1;
    }else{
       return 5.3;
    }
    return 0;
}

然后在服務器上傳輸並執行此功能。

我試圖用模板內部的此功能構建動態庫。 但是模板不支持extern "C" 我嘗試導出的庫是這樣的:

#include < iostream >

  extern "C" {
    template < typename N >
      N testFunc(char * arg) {
        N test = 5;
        std::cout << "Executed| arg is:" << arg << std::endl;
        return test;

      }
  }

然后,我嘗試使用以下命令進行編譯:
g ++-牆-fPIC -c lib.cpp
g ++ -shared -o lib.so lib.o

那么有什么主意我該如何實現呢?

我知道這不是安全的,但僅出於教育目的。

如果我們做一些簡化的假設,那還算不錯:假設您要遠程發送和執行的函數沒有參數,也沒有返回值。 然后,您可以執行以下操作(以下工作示例):

  1. 將源字符串發送到服務器。

  2. 在服務器上,調用gcc來編譯字符串,就像您在問題中所描述的那樣。

  3. 加載共享對象,然后調用該函數。

現在,這可以擴展為您需要的工作量,需要做更多的工作:當客戶端發送該功能時,服務器會保留該功能供以后使用。 稍后,客戶端將包含對函數的調用(包括參數)的字符串作為C ++字符串發送。 服務器將調用字符串附加到函數字符串的底部,然后如此處所示編譯並運行整個字符串。 在此模型中,功能代碼確實可以是模板,並且調用字符串可以包含類型推導適用的任何參數。 缺點是您每次都要編譯函數。 根據函數運行時的瑣碎或時間密集程度,這可能對您或不是您的問題。 當然,有很多方法可以更好地完成所有這些工作,但是我希望這可以作為您的起點。

#include <sys/types.h> 
#include <unistd.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <cstdio> 
#include <string> 
#include <cassert> 
#include <dlfcn.h> 


// Compile this with: g++ test.cpp -ldl 

// Utility: check various calls below and bail out if bad.
int check(int line, int ret, int err = -1)
{
  if (ret == err)
  {
    fprintf(stderr, "on line %d: ", line);
    perror("");
    abort();
  }
  return ret;
}


#define CHECK(X, ...) check(__LINE__, X, ##__VA_ARGS__) 


// Common ipv4 address used by both client and server. 
struct sockaddr_in addr{};

// This runs the client's part.
int client_main()
{
  usleep(100000); // delay to give the server a chance to start. 

  // Connect to the server
  auto sock = CHECK(socket(AF_INET, SOCK_STREAM, 0));
  CHECK(connect(sock, (sockaddr*) &addr, sizeof(addr)));

  // This is the function to be remotely executed.
  std::string msg = R"( 
    #include <cstdio> 

    template <class T> 
    void remote_function(T arg1, T arg2) 
    { 
      if (arg1 < arg2) 
        printf("less\n"); 
      else 
        printf("more\n");   
    } 

    // ---- portion below can be sent separately and appended by server later ----- 

    extern "C" void runit() 
    { 
      remote_function(100, 1000); 
    } 

  )";

  // Send the source
  write(sock, msg.c_str(), msg.size());
  close(sock);

  // Client is done
  return 0;
}

// This is the server's part.
int server_main()
{
  // Listen for incoming connection from client
  auto sock = CHECK(socket(AF_INET, SOCK_STREAM, 0));
  CHECK(bind(sock, (sockaddr*) &addr, sizeof(addr)));
  CHECK(listen(sock, 1));
  struct sockaddr_in peer;
  socklen_t peer_sz = sizeof(peer);
  auto conn = CHECK(accept(sock, (sockaddr*) &peer, &peer_sz));

  // Read the source code from the client
  constexpr size_t maxSize = 1024 * 1024;
  std::string source(maxSize, 0);
  auto sz = CHECK(read(conn, &source[0], maxSize));
  source.resize(sz);
  printf("server got:%s\n", source.c_str());

  // Compile it
  auto gcc = popen("/usr/bin/g++ -o /tmp/_test.so -fPIC -shared -xc++ -", "w");
  assert(gcc);
  CHECK(fwrite(&source[0], 1, source.size(), gcc));
  auto ret = CHECK(pclose(gcc));
  if (ret == 0)
    printf("compiled!\n");
  else
    abort();

  // Load the compiled library
  auto lib = dlopen("/tmp/_test.so", RTLD_LOCAL | RTLD_NOW);
  assert(lib);

  // Run the function
  void (*fun)();
  * (void**) &fun = dlsym(lib, "runit");
  assert(fun);
  (*fun)();

  // Finished
  dlclose(lib);
  return 0;
}



int main()
{
  // Set up address both client and server use to communicate. 
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  addr.sin_port = htons(3333); // some arbitrary port. 

  if (fork())
    return server_main();
  else
    return client_main();
}

僅將兩個對象發送到服務器是不夠的。 您還必須告訴服務器如何比較兩個對象。

例如,假設我有一個客戶端,而您有服務器。 假設我在客戶端上定義了Country類型。 假設表達式netherlands < germany評估為true,因為我定義了operator<(const Country&, const Country&)來比較土地面積。 荷蘭的土地覆蓋面積少於德國,因此netherlands < germany == true ,對嗎?

問題在於您的服務器不知道Country是什么,也不知道如何比較該類型的兩個對象。

即使您的服務器確實了解Country ,我也總是可以提出服務器不知道的另一種類型。 因此,不幸的是,除非我誤解了您的問題,否則我認為不存在一種直接的方法來完成您想要的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM