使用HTTPClient的C客户端GRPC的HTTP/2客户端前言字符串丢失或损坏 [英] HTTP/2 client preface string missing or corrupt for C client gRPC using HTTPClient

查看:28
本文介绍了使用HTTPClient的C客户端GRPC的HTTP/2客户端前言字符串丢失或损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我得到的HTTP/2客户端前言字符串丢失或损坏。";

我的想法是,这与标题设置不正确有关。它很可能是WifiClient/WifiSecureClient的实现。我已经考虑这件事好几个星期了,我被困住了。有什么建议吗?

[更新:答案如下]

客户端是使用Nomb协议缓冲区编译器生成的:

protoc --plugin=protoc-gen-nanopb=~/grpc/nanopb/generator/protoc-gen-nanopb --nanopb_out=. helloworld.proto

Arduino客户端:

DHT dht(DHTPIN, DHTTYPE);

WiFiClient client;
//WiFiClientSecure client;

void setup() {
  Serial.setDebugOutput(true);
  Serial.begin(115200);
  delay(10);

  WiFi.begin("<SSID>", "<My Password>");
  delay(3000);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("WIFI connection failed, reconnecting...");
    delay(2000);
  }

  Serial.print("WiFi connected, ");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting DHT11 sensor...");
  dht.begin();
}


void loop() {
    Serial.print("connecting to ");
    Serial.println(addr);
    
//    client.setInsecure(); 
  if (!client.connect(addr, port)) {
    Serial.println(addr);
    Serial.println(port);
    Serial.println("connection failed");
    Serial.println("wait 5 sec to reconnect...");
    delay(5000);
    return;
  }

  Serial.println("reading humidity/temp...");
  float hum = dht.readHumidity();
  float tmp = dht.readTemperature(true);

  Serial.println(hum);
  Serial.println(tmp);

  if (isnan(hum) || isnan(tmp)) {
    Serial.println("failed to read sensor data");
    delay(2000);
    return;
  }

  float hiCel = dht.computeHeatIndex(tmp, hum, true);

  helloworld_TempEvent temp = helloworld_TempEvent_init_zero;
  temp.deviceId = 1;
  temp.eventId = 0;
  temp.humidity = hum;
  temp.tempCel = tmp;
  temp.heatIdxCel = hiCel;

  sendTemp(temp);
  delay(1000);
}

void sendTemp(helloworld_TempEvent e) {
  uint8_t buffer[128];
  pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

  if (!pb_encode(&stream, helloworld_TempEvent_fields, &e)) {
    Serial.println("failed to encode temp proto");
    Serial.println(PB_GET_ERROR(&stream));
    return;
  }
  
  Serial.print("sending temp...   ");
  Serial.println(e.tempCel);
  client.write(buffer, stream.bytes_written);
}

服务器是使用标准Java协议缓冲区编译器生成的。我唯一更改的是添加了一个临时事件(如下所示)。

... (helloworld template stuff) ...

// The request message containing temperatures
message TempEvent {
    int32 deviceId = 1;
    int32 eventId = 2;
    float humidity = 3;
    float tempCel = 4;
    float heatIdxCel = 5;
}

样例Java客户端可以正常工作。我的问题在于,在使用GRPC发送数据的ESP8266-01 WiFi模块上使用NAMB的简单客户端。

public class Server {

    // Doesn't work
    public static void main(String[] args) throws IOException, InterruptedException {
        io.grpc.Server server = ServerBuilder
                .forPort(8080)
                .addService(new HelloServiceImpl()).build();
        server.start();
        server.awaitTermination();
    }

    // Works just fine
    public static void main(String[] args) throws IOException, InterruptedException {

        try (ServerSocket server = new ServerSocket(8080)) {
            System.out.println("Server accepting connections on port " + server.getLocalPort());
            TemperatureClient tempClient = new TemperatureClient();
            while(true) {

                Socket client = server.accept();
                System.out.println("Client connected using remote port " + client.getPort());

                final Thread t = new Thread(() -> {
                    try {
                        TempEvent p = TempEvent.parseFrom(client.getInputStream());
                        float i = p.getTempCel();
                        System.out.println("TEMP " + i);
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                });
                t.start();
            }
        }
    }

客户端能够访问服务器:

Nov 29, 2021 5:49:30 PM io.grpc.netty.shaded.io.grpc.netty.NettyServerTransport notifyTerminated
INFO: Transport failed
io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 080c10641d0000d84125e17aa0422de4459e42
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:108)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.readClientPrefaceString(Http2ConnectionHandler.java:306)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:239)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:438)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.grpc.netty.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:831)

要调试它,我想先看看是否可以使用grpcurl,但得到的结果是:

localhost@pro ~ % grpcurl -plaintext localhost:50051 list
Failed to list services: server does not support the reflection API

localhost@pro ~ % grpcurl -insecure localhost:50051 list
Failed to dial target host "localhost:50051": tls: first record does not look like a TLS handshake

我开始研究我的实现代码中使用的WifiClient.h实现,但是有没有人有简单的方法来测试它,而不需要深入研究所有东西?我在想这件事应该非常简单。但事实证明,创建一个简单的客户比我想象的要复杂得多。我觉得我好像错过了什么。

来自here上的其他论坛:客户端和服务器没有达成一致。通常这是因为一个是明文,另一个使用TLS。但在某些环境中,这也可能是由于HTTP/1与HTTP/2造成的。

在查看了Go Lang实现之后,我刚刚尝试使用WiFiClientSecure Client.setInsecure();//不起作用,十六进制转储如下所示。

17:36:33.030 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0x41b96938, L:/192.168.0.23:8080 - R:/192.168.0.24:61587] OUTBOUND SETTINGS: ack=false settings={MAX_CONCURRENT_STREAMS=2147483647, INITIAL_WINDOW_SIZE=1048576, MAX_HEADER_LIST_SIZE=8192}
17:36:33.031 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0x41b96938, L:/192.168.0.23:8080 - R:/192.168.0.24:61587] OUTBOUND WINDOW_UPDATE: streamId=0 windowSizeIncrement=983041
17:36:33.063 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0x41b96938, L:/192.168.0.23:8080 - R:/192.168.0.24:61587] OUTBOUND GO_AWAY: lastStreamId=2147483647 errorCode=1 length=126 bytes=485454502f3220636c69656e74207072656661636520737472696e67206d697373696e67206f7220636f72727570742e204865782064756d7020666f72207265...
17:36:33.064 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler - [id: 0x41b96938, L:/192.168.0.23:8080 - R:/192.168.0.24:61587] Sent GOAWAY: lastStreamId '2147483647', errorCode '1', debugData 'HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 16030100d4010000d00303000000005c2f03aae7147c5f36'. Forcing shutdown of the connection.
Dec 10, 2021 5:36:33 PM io.grpc.netty.shaded.io.grpc.netty.NettyServerTransport notifyTerminated
INFO: Transport failed
io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 16030100d4010000d00303000000005c2f03aae7147c5f36
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:108)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.readClientPrefaceString(Http2ConnectionHandler.java:306)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:239)
    at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:438)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
    at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.grpc.netty.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:831)

推荐答案

WiFiClient client;
if (!client.connect(addr, port)) {

这形成了一个基本的TCP连接。但是,GRPC是一个基于HTTP/2复杂协议。目前您只是将原始协议消息写入到一个可以用于通信的TCP套接字,但这肯定不是GRPC服务器所期望的。

Nanopb本身不支持GRPC。正在添加third-party project,但当前未进行维护。

这篇关于使用HTTPClient的C客户端GRPC的HTTP/2客户端前言字符串丢失或损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆