2017-07-25 26 views
-1

GRPCがRHEL 7で動作するように進歩しました。
私たちのアプリケーションは3つのレベルの入れ子と1つの "oneof"キーワード。
他のすべての構造体はうまく動作しますが、これはコード= 14のRPCエラーをもたらします。
アプリケーションのこの部分を可能な限り単純化して、うまくコンパイルして簡単に実行できるようにしました。単純なGRPCサンプルプログラムのRPC失敗コード14

ここでウリの質問に対応するように更新.protoファイルです:

syntax = "proto3"; 

option java_multiple_files = true; 
option java_package = "io.grpc.examples.debug"; 
option java_outer_classname = "DebugProto"; 
option objc_class_prefix = "DEBUG"; 

package DEBUGpackage; 

service DEBUGservice { 
    rpc DEBUG_val_container_get (input_int32_request) returns (outer_container) {} 
} 

message input_int32_request { 
    int32 ival = 1; 
} 

message inner_container { 
    repeated uint32 val_array = 1; 
} 

message middle_container { 
    inner_container vac = 1; 
} 

message other_container { 
    int32 other_val = 1; 
} 

message outer_container { 
    oneof reply { 
    middle_container r1 = 1; 
    other_container r2 = 2; 
    } 
} 

は(彼らはGRPCのウェブサイトの例であるため、このプロトタイプのコード内のjava行がそこにあることに注意してください私たちのコードです。完全にC++で、javaはありません。これは、これらの「オプションjava ...」行なしで実行できることを意味するかどうかわかりません。ここでは当社のサーバーのソースコードです、

#include <iostream> 
#include <memory> 
#include <string> 

#include <grpc++/grpc++.h> 
#include <grpc/support/log.h> 
#include <thread> 
#include <unistd.h> 

#include "debug.grpc.pb.h" 

using grpc::Channel; 
using grpc::ClientAsyncResponseReader; 
using grpc::ClientContext; 
using grpc::CompletionQueue; 
using grpc::Status; 
using DEBUGpackage::input_int32_request; 
using DEBUGpackage::inner_container; 
using DEBUGpackage::middle_container; 
using DEBUGpackage::outer_container; 
using DEBUGpackage::DEBUGservice; 

class DEBUGClient { 
    public: 

    explicit DEBUGClient(std::shared_ptr<Channel> channel) 
      : stub_(DEBUGservice::NewStub(channel)) {} 

    void DEBUG_val_container_get() { 
     std::cout << "in DEBUG_val_container_get" << std::endl; 
     // Data we are sending to the server 
     input_int32_request val; 
     val.set_ival(0); 
     AsyncClientCall* call = new AsyncClientCall; 
     call->response_reader = stub_->AsyncDEBUG_val_container_get(&call->context, val, &cq_); 
     call->response_reader->Finish(&call->reply_, &call->status, (void*)call); 

    } 

    void AsyncCompleteRpc() { 
     void* got_tag; 
     bool ok = false; 

     while (cq_.Next(&got_tag, &ok)) { 
      AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag); 
      GPR_ASSERT(ok); 
      if (call->status.ok()) { 
       if (call->reply_.has_r1()) { 
        std::cout << call << " DEBUG received: " 
          << call->reply_.r1().vac().val_array(0) << std::endl; 
       } 
      } 
      else { 
       std::cout << call << " RPC failed" << std::endl; 
       std::cout << " RPC failure code = " << call->status.error_code() << std::endl; 
       std::cout << " RPC failure message = " << call->status.error_message() << std::endl; 
      } 
      delete call; 
     } 
    } 

    private: 
    struct AsyncClientCall { 
     outer_container reply_; 
     ClientContext context; 
     Status status; 
     std::unique_ptr<ClientAsyncResponseReader<outer_container>> response_reader; 
    }; 

    std::unique_ptr<DEBUGservice::Stub> stub_; 
    CompletionQueue cq_; 
}; 

int main(int argc, char** argv) { 
    DEBUGClient DEBUG0(grpc::CreateChannel("172.16.17.46:50050", grpc::InsecureChannelCredentials())); 
    std::thread thread0_ = std::thread(&DEBUGClient::AsyncCompleteRpc, &DEBUG0); 
    DEBUG0.DEBUG_val_container_get(); 
    sleep(1); 
    std::cout << "Press control-c to quit" << std::endl << std::endl; 
    thread0_.join(); //blocks forever 
    return 0; 
} 

そして:

は、ここに私たちのクライアントのソースコードです

#include <memory> 
#include <iostream> 
#include <string> 
#include <thread> 

#include <grpc++/grpc++.h> 
#include <grpc/support/log.h> 

#include "debug.grpc.pb.h" 

#include <time.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 

using grpc::Server; 
using grpc::ServerAsyncResponseWriter; 
using grpc::ServerBuilder; 
using grpc::ServerContext; 
using grpc::ServerCompletionQueue; 
using grpc::Status; 
using DEBUGpackage::inner_container; 
using DEBUGpackage::input_int32_request; 
using DEBUGpackage::middle_container; 
using DEBUGpackage::outer_container; 
using DEBUGpackage::DEBUGservice; 

std::string save_server_address; 

class ServerImpl final { 

    public: 

    ~ServerImpl() { 
     server_->Shutdown(); 
     cq_->Shutdown(); 
    } 

    void Run() { 
     std::string server_address("0.0.0.0:50050"); 
     ServerBuilder builder; 
     builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); 
     builder.RegisterService(&service_); 
     cq_ = builder.AddCompletionQueue(); 
     server_ = builder.BuildAndStart(); 
     std::cout << "Server listening on " << server_address << std::endl; 
     save_server_address = server_address; 
     HandleRpcs(); 
    } 

    private: 

    class CallData { 
     public: 
     virtual void Proceed() = 0; 
    }; 

    class DebugGetCallData final : public CallData{ 

     public: 

     DebugGetCallData(DEBUGservice::AsyncService* service, ServerCompletionQueue* cq) 
      : service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) { 
      Proceed(); 
     } 
     void Proceed() { 
      if (status_ == CREATE) { 
      status_ = PROCESS; 
      service_->RequestDEBUG_val_container_get(&ctx_, &request_, &responder_, cq_, cq_, this); 
      } else if (status_ == PROCESS) { 
      new DebugGetCallData(service_, cq_); 
      char *portchar; 
      portchar = (char *) save_server_address.c_str(); 
      long cq_addr = (long) cq_; 
      int cq_addr32 = (int) (cq_addr & 0xfffffff); 
      srand(cq_addr32); 
      fprintf(stderr, "%s task started\n", portchar); fflush(stderr); 
      unsigned int return_val = 10; 
      inner_container ic; 
      ic.add_val_array(return_val); 
      middle_container reply_temp; 
      reply_temp.set_allocated_vac(&ic); 
      reply_.set_allocated_r1(&reply_temp); 
      fprintf(stderr, "%s %s task done\n", portchar, "val_container_get"); fflush(stderr); 
      status_ = FINISH; 
      responder_.Finish(reply_, Status::OK, this); 
      } else { 
      GPR_ASSERT(status_ == FINISH); 
      } 
     } 

     private: 

     DEBUGservice::AsyncService* service_; 
     ServerCompletionQueue* cq_; 
     ServerContext ctx_; 
     input_int32_request request_; 
     outer_container reply_; 
     ServerAsyncResponseWriter<outer_container> responder_; 
     enum CallStatus { CREATE, PROCESS, FINISH }; 
     CallStatus status_; 
    }; 

    void HandleRpcs() { 
     new DebugGetCallData(&service_, cq_.get()); 
     void* tag; 
     bool ok; 
     while (true) { 
     GPR_ASSERT(cq_->Next(&tag, &ok)); 
     GPR_ASSERT(ok); 
     static_cast<CallData*>(tag)->Proceed(); 
     } 
    } 

    std::unique_ptr<ServerCompletionQueue> cq_; 
    DEBUGservice::AsyncService service_; 
    std::unique_ptr<Server> server_; 
}; 

int main() { 
    ServerImpl server; 
    server.Run(); 
    return 0; 
} 

出力私はそれがこのようになります実行すると:

[[email protected] debug]$ DEBUG_client2 
in DEBUG_val_container_get 
0xb73ff0 RPC failed 
RPC failure code = 14 
RPC failure message = Endpoint read failed 
Press control-c to quit 

我々 gdbの下でサーバーを実行し、生成された ファイルの場所を見つけました。 "debug.pb.cc"ここで、jus 1行をコメントアウトすると、すべて作業が開始されます。

は、ここで生成されたファイル「debug.pb.cc」の関連作品だ:

middle_container::~middle_container() { 
    // @@protoc_insertion_point(destructor:DEBUGpackage.middle_container) 
    SharedDtor(); 
} 

void middle_container::SharedDtor() { 
    if (this != internal_default_instance()) { 
    delete vac_; // comment out this one line, to make the problem go away 
    } 
} 

「vac_を削除」の行はどちらか、すでに削除されているストレージを削除しようとする試みであるように見える、またはありますどこか他の場所で削除しようとしています。してください、誰かがこれを調べることができますか? [下のファイルは、このコードを生成し、この時点で問題をデバッグするために使用するファイルです。]

GRPCでバグを発見したのかどうか、 。

+0

実際にあなたのサブタイプに複数のサブタイプを入れたらどうなりますか?今はそれほど重要ではありません。 – Uli

+0

@uli お返事ありがとうございます!別のサブタイプを追加しましたが、その動作は同じでした。私はまた、私が見ている振る舞いのプリントアウトを加えました。 –

+0

残念ながら、私はgrpc Cの実装についてはわかりません。 grpc.ioのウェブサイトまたはhttps://github.com/grpc/grpc/tree/master/docにエラーコード14に関する情報はありますか?私はエラーコードを含むいくつかの文書を思い出しているようです。ここに返信しないと、おそらくgrpc Googleグループの誰かが助けることができます。 – Uli

答えて

0

問題は、サーバーのスタックにmiddle_container reply_tmpが割り当てられていることです。その結果、あなたはスコープから抜けてすぐに破壊されます。当時、あなたはFinishを呼び出しましたが、その結果をまだ待っていませんでした。これは非同期サーバーなので、データを受け取るまでデータは有効な状態を維持しなければなりません。これは、あなたのケースでデストラクタを手動で編集する理由です。基本的にはデストラクタを無効にしています(結果としてメモリが漏れています)。

+0

@VijayPaiありがとうございます。 私はこの全体を少し弱くしています。「仕上げ」の結果を待っています。 我々のコードは/ greeter_async_server.cc と 例/ CPP/helloworldの/ greeter_async_client2.cc 例/ CPP/HelloWorldの中に見出さgrpcサンプルコードに基づいていました。 このコードのどこでFinishの結果を待っているかを指摘できれば、とても感謝しています。 –

関連する問題