I've created a gRPC server using proto3 and Python for basic client-server communication. When I start my server application, it communicates with the client as expected. However, I notice that the HTTP protocol being used is HTTP/1.1, as observed in Wireshark logs.
Sample code:
import grpc
from concurrent import futures
from my_proto import my_service_pb2_grpc
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
my_service_pb2_grpc.add_MyServiceServicer_to_server(MyService(), server)
# Adding insecure port
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
I would like my gRPC server to communicate using the HTTP/2 protocol over an insecure channel.
Reference: I came across this GitHub issue which states that HTTP/2 support is typically associated with secure channels. However, I’d like to confirm if there is a way to ensure HTTP/2 usage on an insecure channel.
Despite configuring the server to use add_insecure_port, the communication seems to default to HTTP/1.1. I expected it to use HTTP/2, which is the default for gRPC.
server.add_secure_port(f"{ip}:{port}",credentials)
Your code is correct per the gRPC site's Python helloworld server and it will be using HTTP/2
The Python gRPC implementation shares a C++ foundation with several languages (C++, Java, etc.). The Golang implementation is different (grpc-go).
For Python (and the other languages), Troubleshooting is available through environment variables e.g. GRPC_TRACE
There are various ways that you can test for HTTP/2:
The Python client uses the shared library and shares troubleshooting, so you can:
GRPC_TRACE=http \
python3 your_client.py
chttp2_transport.cc:1227] HTTP:CLI: Transport 0x7fe4a0001170 allocating new grpc_chttp2_stream 0x7fe4a0006650 to id 1
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> WRITING+MORE [START_NEW_STREAM]
chttp2_transport.cc:1293] complete_closure_step: t=0x7fe4a0001170 0x7fe4a0006458 refs=3 flags=0x0001 desc=op->on_complete err=OK write_state=WRITING+MORE whence=(null):-1
writing.cc:447] W:0x7fe4a0001170 CLIENT[1] im-(sent,send)=(0,1)
chttp2_transport.cc:1293] complete_closure_step: t=0x7fe4a0001170 0x7fe4a0006458 refs=2 flags=0x0001 desc=send_initial_metadata_finished err=OK write_state=WRITING+MORE whence=(null):-1
chttp2_transport.cc:1293] complete_closure_step: t=0x7fe4a0001170 0x7fe4a0006458 refs=1 flags=0x0001 desc=send_trailing_metadata_finished err=OK write_state=WRITING+MORE whence=(null):-1
chttp2_transport.cc:1293] complete_closure_step: t=0x7fe4a0001170 0x7fe4a0006458 refs=0 flags=0x0001 desc=on_write_finished_cb err=OK write_state=WRITING+MORE whence=(null):-1
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING+MORE -> WRITING [begin write in current thread]
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> IDLE [finish writing]
parsing.cc:335] INCOMING[0x7fe4a0001170]: PING len:8 id:0x00000000
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state IDLE -> WRITING [PING_RESPONSE]
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> WRITING+MORE [begin partial write in background]
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING+MORE -> WRITING [continue writing]
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> IDLE [begin writing nothing]
parsing.cc:335] INCOMING[0x7fe4a0001170]: HEADERS:END_HEADERS len:78 id:0x00000001
parsing.cc:758] parsing initial_metadata
parsing.cc:335] INCOMING[0x7fe4a0001170]: DATA len:18 id:0x00000001
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state IDLE -> WRITING [BDP_PING]
parsing.cc:335] INCOMING[0x7fe4a0001170]: HEADERS:END_STREAM:END_HEADERS len:30 id:0x00000001
parsing.cc:764] parsing trailing_metadata
parsing.cc:335] INCOMING[0x7fe4a0001170]: WINDOW_UPDATE len:4 id:0x00000000
writing.cc:139] CLIENT[0x7fe4a0001170]: Ping e209562f587e244e sent [ipv6:%5B::1%5D:50051]: max_pings_without_data: 2, pings_before_data_required: 1, last_ping_sent_time_: @1324ms
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> WRITING [begin write in current thread]
chttp2_transport.cc:931] W:0x7fe4a0001170 CLIENT [ipv6:%5B::1%5D:50051] state WRITING -> IDLE [finish writing]
NOTE The use of
chttp2_transport
and gRPC specific message content.
A known-good gRPC tool that uses the Golang gRPC implementation and so requires different environment variables (unfortunately):
GODEBUG=http2debug=2 \
grpcurl \
-vv \
-plaintext \
-proto your.proto \
localhost:50051 \
your-package.your-server/YourMethod
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote SETTINGS len=0
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read SETTINGS len=30, settings: MAX_CONCURRENT_STREAMS=2147483647, INITIAL_WINDOW_SIZE=4194304, MAX_FRAME_SIZE=4194304, MAX_HEADER_LIST_SIZE=16384, UNKNOWN_SETTING_65027=1
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read WINDOW_UPDATE len=4 (conn) incr=4128769
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read SETTINGS flags=ACK len=0
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote SETTINGS flags=ACK len=0
Resolved method descriptor:
// Sends a greeting
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
Request metadata to send:
(empty)
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote HEADERS flags=END_HEADERS stream=1 len=120
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote DATA flags=END_STREAM stream=1 len=5 data="\x00\x00\x00\x00\x00"
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read PING len=8 ping=" \xe1\xcd\xe3/\x9fC\x9f"
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote PING flags=ACK len=8 ping=" \xe1\xcd\xe3/\x9fC\x9f"
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read HEADERS flags=END_HEADERS stream=1 len=78
2024/08/13 10:48:27 http2: decoded hpack field header field ":status" = "200"
2024/08/13 10:48:27 http2: decoded hpack field header field "content-type" = "application/grpc"
2024/08/13 10:48:27 http2: decoded hpack field header field "grpc-accept-encoding" = "identity, deflate, gzip"
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read DATA stream=1 len=15 data="\x00\x00\x00\x00\n\n\bHello, !"
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read HEADERS flags=END_STREAM|END_HEADERS stream=1 len=30
2024/08/13 10:48:27 http2: decoded hpack field header field "grpc-status" = "0"
2024/08/13 10:48:27 http2: decoded hpack field header field "grpc-message" = ""
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read WINDOW_UPDATE len=4 (conn) incr=5
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote WINDOW_UPDATE len=4 (conn) incr=15
2024/08/13 10:48:27 http2: Framer 0xc00042a000: wrote PING len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
Response headers received:
content-type: application/grpc
grpc-accept-encoding: identity, deflate, gzip
Estimated response size: 10 bytes
Response contents:
{
"message": "Hello, !"
}
Response trailers received:
(empty)
Sent 0 requests and received 1 response
2024/08/13 10:48:27 http2: Framer 0xc00042a000: read PING flags=ACK len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
Timing Data: 5.519619ms
Dial: 1.590924ms
BlockingDial: 1.571091ms
InvokeRPC: 3.007197ms