Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
サーバーフレームワークの仕組みが気になったので車輪の再発明をしてみた
Search
Yuta Tomiyama
March 12, 2022
Programming
260
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
サーバーフレームワークの仕組みが気になったので車輪の再発明をしてみた
2022/03/12 全国学生エンジニア交流会「NSEEM」にて発表
https://github.com/yt8492/NativeServer
Yuta Tomiyama
March 12, 2022
More Decks by Yuta Tomiyama
See All by Yuta Tomiyama
ビルドプロセスをデバッグしよう!
yt8492
2
520
モバイルアプリ開発を始めよう!
yt8492
0
130
Git勉強会
yt8492
0
240
なんでもやってみる勇気
yt8492
0
140
Android Autoが思ったよりしんどい話
yt8492
0
260
apollo-kotlinにcontributeした話
yt8492
0
200
DMM TVのSDカードダウンロード機能を実装した話
yt8492
1
1k
今だからこそ知りたいKotlin Multiplatform
yt8492
0
360
State management and API calls in Jetpack Compose: Learning Apollo + Jetpack Compose through React Hooks
yt8492
0
1.4k
Other Decks in Programming
See All in Programming
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
5
5k
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
350
dotNET_vulnclicker_intro.pdf
deka_morita
0
140
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
190
Kotlinの15年とServer-Side Kotlin
n_takehata
1
150
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
140
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
8.4k
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
270
GemmaをJevのように使ってみる / Use Gemma like Jev
kishida
5
780
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
170
S3 TablesのIcebergデータに、AIエージェントからアクセスしてみた / 20261016developersio2026joetsu-accessing-iceberg-in-s3tables-via-agent
kasacchiful
PRO
0
110
Featured
See All Featured
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.2k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
340
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.2k
Mind Mapping
helmedeiros
1
400
Utilizing Notion as your number one productivity tool
mfonobong
4
620
Building the Perfect Custom Keyboard
takai
2
900
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Into the Great Unknown - MozCon
thekraken
41
2.8k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
490
Navigating Weather and Climate Data
rabernat
0
550
Transcript
サーバーフレームワークの 仕組みが気になったので 車輪の再発明をしてみた 2022/03/12 NSEEM
自己紹介 HN: マヤミト ID: yt8492 会津大学 学部4年 OtakuProject運営 GitHub: https://github.com/yt8492
趣味: Kotlin, Twitter, ウマ娘 Twitter: yt8492
バックエンドの開発してる人
フレームワークの仕組み、気になりません?
じゃあ作ってみよう!w
今回のテーマ: サーバーフレームワーク自作
やること - TCPのソケット通信をラップしてHTTP通信を実装 - それをもとにフレームワークを実装 - 使用言語はKotlin/Native (苦行) - Cの標準関数のブリッジくらいしか提供されてないので逆に勉強になると思った
- もしこのLTを見ている人が同じことをしたいと思ったら素直に Kotlin/JVMでやることをおすすめしま す
HTTP通信 - HTTPの仕様はRFCで定義されている - 今回はHTTP/1.1でやるのでRFC2616 - TCPのリクエストをどのように解釈して、レスポンスをどのような形式で送ればいいかなどが書かれ ている - リクエストを解釈してレスポンスを返せれば良い
- リクエスト - リクエストライン - ヘッダ - ボディ - レスポンス - ステータスライン - ヘッダ - ボディ
HTTPリクエストを解釈する - TCPのリクエストから以下を解釈できればよい - リクエストライン - ヘッダ - ボディ -
RFCではこのように定義されている - Request = Request-Line *(( general-header | request-header | entity-header ) CRLF) CRLF [ message-body ]
リクエストのリクエストラインを解釈する - RFCではこのように定義されている - Request-Line = Method SP Request-URI SP
HTTP-Version CRLF - メソッド、URI、HTTPバージョンが空白区切りで、最後に CRLF(改行)がある - つまり、ソケット通信で以下のことができればよさそう - CRLFが現れるまで通信を読み込む - 読み込んだバイト列を文字列として扱う - 空白で区切り、それをメソッド、 URI、HTTPバージョンとする
リクエストのリクエストラインを解釈する
リクエストのヘッダを解釈する - ヘッダフィールドのフォーマットは以下のように定義されている - message-header = field-name ":" [ field-value
] field-name = token field-value = *( field-content | LWS ) field-content = <field-value を構成し、*TEXT あるいはtoken, separators, quoted-string を連結したものから成る OCTET> - 名前と値がコロン区切りになっていて、値は前後に 0個以上の空白を含む場合がある - リクエストのヘッダは 0個以上のヘッダフィールドが CRLF区切りになっていて、 CRLFのみの行がヘッ ダの終わりになる
リクエストのヘッダを解釈する - ソケット通信で以下のことができればよさそう - CRLFが現れるまで読み込む - 読み込んだ結果が空であればヘッダの終わり、そうでなければコロンで区切ってそれを名前と値と する - 終わりでない場合は繰り返す
リクエストのボディを解釈する - ボディは以下のように定義されている - message-body = entity-body | <Transfer-Encoding にてエンコードされた
entity-body> - ヘッダに Content-Length や Transfer-Encoding 各ヘッダフィールドを含むとボディが存在し、 な ければボディが空 - Content-Lengthが指定されている場合はそのバイト数だけボディをよみこむ
リクエストのボディを解釈する - 簡単のためTransfer-Encodingは今回考慮しないことに🙏
レスポンスをHTTPの形式にする - 以下の情報をTCPのレスポンスとして返せればよい - ステータスライン - ヘッダ - ボディ -
RFCではこのように定義されている - Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ]
ステータスラインをTCPのレスポンスに書き込む - RFCではこのように定義されている - Status-Line = HTTP-Version SP Status-Code SP
Reason-Phrase CRLF - つまり、ソケット通信で以下のことができるとよさそう - HTTPバージョンと区切りの空白を書き込む - ステータスコードと区切りの空白を書き込む - 説明句と終端のCRLFを書き込む
ヘッダをTCPのレスポンスに書き込む - 基本的にはリクエストと同じ - ヘッダフィールドの名前と値がコロン区切りになっていて、 CRLFで終わる - CRLFのみの行がヘッダの終わり
ボディをTCPのレスポンスに書き込む - 今回はTransfer-Encodingを考慮しないので単純にボディとして渡されたバイト列 をそのまま書き込む
ここまでがRFCに沿った実装
ここからフレームワークとしての便利実装
フレームワークなら便利であってほしい - HTTPを最低限実装しただけではバックエンド開発に使うには厳しい - Nodeのhttpモジュールとかだけでやろうとするとしんどい - フレームワークなら次のような機能があってほしい - クエリパラメータ -
パスパラメータ - ルーティング
クエリパラメータの取得 - 今回は以下のようになっているという前提で扱う - URIを?で区切った後ろの部分 - 名前=値という形でフィールドが構成され、それが &で連結されている - 名前と値はURLエンコードされる
- 以下のように実装する - URIを?で区切った後ろの部分を取得する - 空でなければさらに &で区切る - 更に=で区切り、それぞれを URLデコードする
ルーティング - 今回はユーザーが以下のように使えるように実装する - get("/hoge") { … }, post("/fuga") {
… } のように、メソッドごとに関数が用意されていて、それ に パスを指定し、ラムダ関数の中で実際にリクエストを受け取ったときの処理を書く - 次のように実装する - ユーザーが get("/hoge") { … } のように関数を呼び出すとハンドラが追加される - ソケットから受け取った TCPのリクエストをHTTPのリクエストとして解釈する - 受け取ったリクエストの URIをもとにどのハンドラで処理するべきか評価し、最も評価度が高いハン ドラに実際に処理をさせる - 処理の結果ユーザーが生成したレスポンスのインスタンスを実際に HTTPのレスポンスとしてTCP のソケットに書き込む
ハンドラの実装 - ハンドラ自体はパスとHTTPメソッドと処理をする関数を持つだけ - ユーザーがHTTPのリクエストに対応した関数を呼び出すとハンドラのリストに追加 されていく
リクエストをハンドラにマッチさせる - 同じリクエストでも複数のハンドラにマッチする可能性がある - /hoge/fuga は /hoge/fuga, /hoge/:param, /hoge/* にマッチする可能性がある
- マッチ度が高いのは /hoge/fuga > /hoge/:param > /hoge/* - これを実際にリクエストが来るたびに行う - ハンドラのパスを/で区切り、それぞれが定数、パスパラメータ、ワイルドカードかど うかによってそのハンドラがマッチした場合の評価度を計算する - パスパラメータを持つ場合は実際にそれを取り出す - ソースコードは結構長くなったのでGitHubまで見に来て
使う側はこんな感じで使える
実際のソースコードはこちら - yt8492/NativeServer https://github.com/yt8492/NativeServer
まとめ - ソケット通信からサーバーフレームワークの実装できた - RFCを読みながら実装するとかなり勉強になる - 自分の知らなかった仕様に出会える - 実際に動くと感動
みんなも車輪の再発明しよう! 楽しいよ!