---
title: MagicOnion + quiche + Unityで gRPC over HTTP/3を実現する
tags: 
author: [nuskey](https://www.docswell.com/user/nuskey)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/KJ4W1PZ171.jpg?width=480
description: C# Kaigi 2026登壇資料です https://csharpkaigi.connpass.com/event/394163/
published: September 19, 26
canonical: https://www.docswell.com/s/nuskey/ZN788L-magiconion-quiche-unity
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/KJ4W1PZ171.jpg)

MagicOnion + quiche + Unityで
gRPC over HTTP/3を実現する
&gt; nuskey8/QuicHttpHandler
2026/09/19 @docomo R&amp;D OPEN LAB ODAIBA
C# Kaigi 2026
#csharpkaigi
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/LE1YG9R57G.jpg)

- @nuskey8 (a.k.a @annulusgames)
- 大学生です
- Unity・C#・RustのOSS開発やってます
- インターンでパフォーマンスチューニングのお仕事をしてます
#csharpkaigi
#
#
自己紹介
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/GEWGKQ1WJ2.jpg)

- QUIC・HTTP/3とは何か
- MagicOnionとgRPC over HTTP/3
- UnityでQUICを動かす
#csharpkaigi
#
#
セッションの内容
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/47ZLZWP2J3.jpg)

# QUIC・HTTP/3とは何か
#csharpkaigi
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/YJ6WZG46JV.jpg)

- 従来のHTTP/1.1やHTTP/2ではTCPが使われていた
- TCPは信頼性のある通信を提供する一方、いくつか問題があった
- 順序を保証する都合上、パケットが欠けると再送を待機する必要がある
(Head of Lineブロッキング問題)
- HTTP/2ではストリームを多重化することができるが、結局TCPを使うので
1パケットのロスで全てのストリームが停止してしまう
- UDPにはこれらの問題がない代わりに、単体では信頼性が必要な通信には向かない
- 順序も再送も何も保証がない
#csharpkaigi
#
#
TCP・UDPの問題
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/GJ5MWVQ5J4.jpg)

- UDP上に構築されたトランスポートプロトコル
- ストリーム単位でデータの整合性を確保
- TCPのようなHead of Lineブロッキング問題が起きない
- コネクションマイグレーションが可能
- Wi-fiからスマホの回線に変わるなどしてもコネクションを維持できる
- コネクションの確立が速い
- 1-RTTでハンドシェイクを行う
#csharpkaigi
#
#
QUICの登場
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/LE3W4DV5E5.jpg)

- QUICをトランスポートプロトコルに利用した新しいHTTPのバージョン
- HTTP/2をベースにしつつ、QUICの仕様に合わせて再構築
- ストリーム管理やウィンドウ制御はQUIC側に吸収
- 届いたパケットの到着順に依存しないように仕様を再設計(HPACK QPACKなど)
7
&gt;
-
#csharpkaigi
#
#
そしてHTTP/3へ


# Page. 8

![Page Image](https://bcdn.docswell.com/page/8EDKQP8Y7G.jpg)

# C#におけるQUIC・HTTP/3対応の現在位置
#csharpkaigi
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/V7PKLN82J8.jpg)

- MsQuicをベースとした実装が.NET 5で(内部用として)導入
- これはSystem.Net.Quicとして.NET 7で公開され、.NET 9で安定化された
- https: learn.microsoft.com/ja-jp/dotnet/fundamentals/
networking/quic/quic-overview
- MsQuicに依存する都合上、プラットフォームの制約がある
- Windowsの場合はWindows11以降
- Linux/macOSではlibmsquicパッケージが必要
- それ以外のプラットフォームは基本的にサポート対象外
/
/
#csharpkaigi
#
#
.NETでQUICを動かす
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/2JVVQKNXJQ.jpg)

- Kestrel(ASP.NET Core内部のWebサーバー)は.NET 7以降で正式にHTTP/3対応
- デフォルトでは無効なので以下のような設定が必要
- HTTPSが必須であることに注意
#csharpkaigi
#
#
ASP.NET CoreでHTTP/3を動かす
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/5EGLWQKRJL.jpg)

- HttpClientも.NET 7以降で正式にHTTP/3対応
- HttpVersion.Version30を指定すれば普通に動く
- 内部的にはデフォルトのHttpMessageHandler実装である
SocketsHttpHandlerがHTTP/3をサポートしている
#csharpkaigi
#
#
HttpClientでHTTP/3を使う
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/4JQY3KNY7P.jpg)

- HttpClientは実はほとんどガワに過ぎず、実際の通信層は
HttpMessageHandlerとして抽象化される
- つまり、これを差し替えることで通信層を丸ごと置き換えることができる
- これは後で出てくるので前提知識として覚えておいてください
#csharpkaigi
#
#
[補足] HttpMessageHandlerについて
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/K74W1PGZE1.jpg)

- QUIC・HTTP/3が.NET 7あたりからサポートされている
- 実装はMsQuicを基盤としている
- その都合上、QUICが利用できるプラットフォームに制約がある
- デスクトップでは動くが、それ以外では動かない
#csharpkaigi
#
#
C#におけるQUIC・HTTP/3対応の現在位置
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/LJ1YG9DDEG.jpg)

# MagicOnionとgRPC over HTTP/3
#csharpkaigi
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/GJWGKQY872.jpg)

- 「.NET プラットフォーム向けの双方向リアルタイム通信を提供する
モダンなRPCフレームワーク」
- https: github.com/cysharp/MagicOnion
- サーバー・クライアントをC#で統一
- .protoを使わず、C#のinterfaceをスキーマとした型安全なRPCを行う
- 必要なコードはSource Generatorがコンパイル時に生成
/
/
#csharpkaigi
#
#
MagicOnionとは？
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/4EZLZWX973.jpg)

C#のinterfaceがそのままスキーマになる
#csharpkaigi
#
#
MagicOnionとは？
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/Y76WZG4D7V.jpg)

- grpc-dotnetは他の言語に先んじてgRPC over HTTP/3に対応していた
- 現在はデフォルトで対応、HttpVersion.Version30で明示もできる
#csharpkaigi
#
#
C#でgRPC over HTTP/3
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/G75MWVQ874.jpg)

- MagicOnionの実装はASP.NET Coreおよびgrpc-dotnetの上に築かれている
- 最新の.NETなら何もせずともHTTP/3で動かすことができる
#csharpkaigi
#
#
MagicOnionでgRPC over HTTP/3？
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/9J29Q3PVER.jpg)

？
- MagicOnionを採用するプロダクトでは、クライアントがUnityであるケースも多い
- モバイル向けタイトルでリアルタイム通信を行う場合、
QUIC・HTTP/3を利用することで得られる恩恵はとても大きい
- UnityでもgRPC over HTTP/3したい、が
19
.
.
.
.
.
.
#csharpkaigi
#
#
Unityは


# Page. 20

![Page Image](https://bcdn.docswell.com/page/DEY4W15QJM.jpg)

# UnityでQUICを動かす
#csharpkaigi
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/VJNY92N278.jpg)

- Unityのランタイムは未だMono
- .NET Standard 2.1相当の機能しか動かない
- C#のバージョンも9.0のまま
(実はちょっとしたハックで言語バージョンは上げられるが
)
- Unity7でようやくCoreCLR移行が実現するが、もう数年はUnity6が主役
- CoreCLRになってもIL2CPPは必要
- モバイルやコンソールなどのプラットフォーム向けにIL2CPPは引き続き現役
21
.
.
#csharpkaigi
#
#
Unityのランタイム事情


# Page. 22

![Page Image](https://bcdn.docswell.com/page/YE9P21RDJ3.jpg)

- 当然.NET側のQUIC・HTTP/3サポートは使えない
- なんならUnity6.3以前はHTTP/2すら標準サポートがない
- 仮にCoreCLRが来たとしても、デスクトップ以外のプラットフォームでは厳しい
- System.Net.Quicがモバイルで動くのかが怪しい
- MsQuic自体は対応してる(動くだけで正式にサポートしているわけではない)
ので動かせなくはなさそうだが…
22
.
.
.
#csharpkaigi
#
#
つまり


# Page. 23

![Page Image](https://bcdn.docswell.com/page/GE8D54W5ED.jpg)

- C#で自前でQUIC・HTTP/3を実装する？
- 独自実装でQUIC・HTTP/3の膨大な仕様をカバーするのは非現実的
- 既存のライブラリに頼った方がいい
- MsQuicをビルドして使う？
- 実装の信頼性は最高レベル
- C実装なのでポータビリティも高い
- ただしMsQuicの実装範囲はQUICまで、HTTP/3部分は独自実装が必要
- どうしよう？
#csharpkaigi
#
#
一体どうすれば？
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/LELMY6N37R.jpg)

- Rust製のHTTP/3ライブラリをネイティブプラグインとして持ち込む
- Rustの豊富なエコシステムを利用できる
- ビルド周りもcargoがほとんど面倒を見てくれる
- ただしコンソールを除く、今回はデスクトップ・モバイルのみを考えます
#csharpkaigi
#
#
そうだ、Rustを使おう
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/4JMYN5XMJW.jpg)

- Cysharp/YetAnotherHttpHandler
- Unity向けのHTTP/2対応のHttpMessageHandler実装
- Rustのhyper+rustlsをベースとした実装をFFIでC#に持ち込む
#csharpkaigi
#
#
Rust+Unityの先行事例
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/PJR9D3NL79.jpg)

- Rust製のQUIC・HTTP/3ライブラリはいくつかある
- quiche、quinn、h3、などなど…
- 具体的な比較は長くなるので割愛
- 詳しくは以下の記事が参考になります
- https: qiita.com/takehara-ryo/items/1f3e19b54bd6fffcba77
/
/
#csharpkaigi
#
#
ライブラリの選定
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/PEXQ1486JX.jpg)

- 信頼性が高く、パフォーマンス面にも優れたquicheを利用する
- CloudflareによるQUIC・HTTP/3実装、モバイルでも動く
- 実践投入されており信頼性が高い
- そのままだとAPIが低レベルで扱いにくい
- tokio-quicheをベースとして実装する
- イベントループの管理は全てRust(tokio)側に置く
- 高レベルなC APIを公開してC#側で叩くだけで済むように
#csharpkaigi
#
#
今回の選択肢
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/3EK92ZKGED.jpg)

- 細かい実装については割愛
- C#側から非同期で扱うための工夫がちょいちょい入ってます
- ほとんどAIが書いてくれています、いい時代になったものです
#csharpkaigi
#
#
Rust側の実装
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/L73W4DZ575.jpg)

- Rust側で公開したC APIに合わせてFFIを手書きするのは大変
- Cysharp/csbindgenを用いてこれを自動化
- build.rsで設定するとビルド時に
C#バインディングを自動生成する
29
.
.
#csharpkaigi
#
#
バインディングの自動生成(csbindgen)


# Page. 30

![Page Image](https://bcdn.docswell.com/page/87DKQPRYJG.jpg)

- csbindgenで生成した低レベルAPIを叩くHttpMessageHandlerを実装
- これによりHttpClientの通信層をRust実装で差し替えられる
- これだけで済めば良かったが
30
.
.
.
#csharpkaigi
#
#
HttpMessageHandlerとしてラップ


# Page. 31

![Page Image](https://bcdn.docswell.com/page/VJPKLNW2E8.jpg)

- quicheの公開APIではHttpMessageHandlerの実装に必要な情報が足りない
- Trailerヘッダが拾えない
- これはgRPC対応に必須
- RESET_STREAMの理由が捨てられている
- 接続直後のQLOGが取得できない
- etc.
- quicheをforkして改造を施すことで一旦解決
#csharpkaigi
#
#
quiche側の改造
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/2EVVQK8XEQ.jpg)

- 通信のたびに同期I/Oはパフォーマンス的に許されない
- Rust側からPipeに書き込ませ、C#側から読み取るのが基本
- 普通にC APIを作ると同期処理になるので、最初から非同期にすることを
前提に設計しないと難しい
- TaskCompletionSource&lt;T&gt;でTaskに変換
- TaskCreationOptions.RunContinuationsAsynchronouslyを設定すること
- これを忘れると継続処理が同期実行されるため、
Rust側のワーカースレッドをブロックする可能性がある
#csharpkaigi
#
#
System.IO.Pipelinesを用いた非同期I/O
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/57GLWQ5REL.jpg)

- HTTP/3で動くMagicOnionサーバーを立てておき、UnityからUnaryを叩いてみる
#csharpkaigi
#
#
Unityで動作させる
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/4EQY3KZYJP.jpg)

#csharpkaigi
#
#
Unityで動作させる
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/KJ4W1P3Z71.jpg)

- 今回の実装をnuskey8/QuicHttpHandlerとして公開
- Unity向けの想定ですが、一応.NET/Unityの両方で動きます
- HTTP/3限定なので、HTTP/1.1や2も同時にサポートしたい場合は
DelegatingHandlerでYetAnotherHttpHandlerなどにフォールバックしてください
#csharpkaigi
#
#
ライブラリ化しました
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/LE1YG91D7G.jpg)

# まとめ
#csharpkaigi
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/GEWGKQ88J2.jpg)

- .NET 7以降ではMsQuicベースのQUIC・HTTP/3実装がある
- Unityでは動かせないため、quicheベースのRust実装を持ち込んで解決
- C#+Rustはいいぞ
#csharpkaigi
#
#
まとめ
37


# Page. 38

![Page Image](https://bcdn.docswell.com/page/47ZLZW89J3.jpg)

# Thank you for listening!
#csharpkaigi
38


