「HTTP/2 クライアントのプリフェイス文字列が見つからないか壊れています」というメッセージが表示されます。
私の考えでは、ヘッダーが正しく設定されていないことに関係していると思います。おそらく WifiClient/WifiSecureClient の実装です。私はこれについて数週間以上考えてきましたが、行き詰まっています。何かアドバイス?
[更新: 以下の回答]
クライアントは nanopb プロトコル バッファ コンパイラを使用して生成されました。
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 プロトコル バッファ コンパイラを使用して生成されました。私が変更した唯一のことは、TempEvent (以下) を追加することでした。
... (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 モジュールで nanopb を使用する単純なクライアントです。
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 の実装を調べ始めましたが、すべてを掘り下げずにこれをテストする簡単な方法について何かアイデアはありますか? これは非常に単純なはずだと思っていました...しかし、単純なクライアントを生成するには、思ったよりもはるかに複雑であることが判明しました。ここで何かが欠けているように感じます。
ここの他のフォーラムから: 「クライアントとサーバーが一致していません。通常、これは一方がプレーンテキストで、もう一方が TLS を使用しているためです。しかし、特定の環境では HTTP/1 と HTTP/2 が原因である可能性もあります。」
Go Lang の実装を見た後、WiFiClientSecure client.setInsecure(); を使用してみました。// 機能しませんでした。16 進ダンプは以下のとおりです。
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)