経緯
今G's Academyというところで勉強しているんですが、そこの課題でHTTP通信を扱った際にドはまりしまして。提出期限を大幅に過ぎてしまいました。
これはもう何となくで済ましてしまってはダメだということで、通信の勉強をやり直しています。
ただ、いきなりOSIがどうたらと言葉で言われてもイメージがつかず...。手を動かしながら学べる教材がないか探してみたところ、この本が見つかりました。
サンプルコードがJavaなんで、Kotlinの勉強をかねてこの本の内容をKotlinで書いてみることにしました。
自分が書いたコードはGitHubにあげたので、記事の最後にリンクを張ります。
環境
Kotlin version 1.3.41-release-150 (JRE 1.8.0_151-b12)
IntelliJ IDEA 2019.2 (Community Edition)
現状
htmlファイルとそれに含まれているリソースをレスポンスとして返せるところまで来ました。

工夫
ただサンプルコードをKotlinに置き換えるだけだとつまらないので、以下の点を工夫しながら焼き直しています。
- Kotlinならではの文法が使えそうな個所は積極的に使う(ifやwhenを式として使う、スコープ関数の活用、エルビス演算子を利用したnullチェックなど)
- 副作用を減らすために極力varではなくvalを使う
- 繰り返しで書くとvarを使わざるを得なくなる場合があるので、その際は再帰で書く←はまった点があるので後述
最近会ったインド人エンジニアにHaskellを勧めてもらいました。彼曰く"It's very difficult to write wrong code in Haskell(Haskellで間違ったコードを書くのは難しい)"とのこと。軽くHaskellと関数型言語についてググったのですが、副作用がないというのがバグを少なくできる一つの理由だそうです。
Kotlinでも副作用を意識して書いた方がいいんだろうなと思ったので最後の2つを足しました。今まで再帰で処理を書いたことがなかったので、練習するいい機会になりますし。
あと、ほら、再帰をサラッと使えるエンジニアってイケテル感じがするじゃないですか...こんな風に感じるのって私だけですか?
はまった点
再帰のネストを深くしすぎて、StackOverFlowになった
上記の通り、再帰を使って書こうとしたんですが、本のサンプル通り1バイトずつ読み込む処理を書いていました。(書き直す前のが残っていないので、厳密にはこの通りじゃなかったかもしれません)
private fun readByte(readBytes : String, input : InputStream) : String {
val endOfFile = -1
val byte = input.read().toChar()
return if (byte == endOfFile.toChar()) {
readBytes
} else {
readByte(readBytes + byte, input)
}
}
20KBの画像ファイルを読み込もうとしたら、20,000回この関数がネストすることになりますね。スタックが足りるわけない
バッファーを使った書き方に変えたら問題なく動きました...と言いたいのですがまだもう一つ問題が
ファイアウォールを解除し忘れてた
本の方には「プログラムの初回実行時にファイアウォールの設定を聞かれます」と書いてあったのですが私の環境では何事もなく実行されました。
なのでコントロールパネルから自分でファイアウォールの設定をし、使っていたポートをプライベートネットワークのみに公開しました。
勉強になったこと(改めて実感したこと)
以下の2点はエンジニアとして知っていて当たり前だろってことなんですが、知識として知っていても実感としては持っていませんでした。
クライアント・サーバー間であれ、ローカルのファイル間であれ、データをやり取りする方法には大差ない
「基礎からのwebアプリケーション開発入門」のサンプルコードを読んで一番驚いたのが、クライアントからのリクエストの受け取り方がファイルの読み取りとほぼ同じだった点です。
違うのは、ポートを指定してクライアントから接続されるのを待つか、読み込みたいファイルのパスを指定するかです。
データの流れ=ストリーム(stream, 小川)の始端と終端さえ決めてしまえば、後は通信もファイル読み込みも全く同じ処理でできる ということですね。
テキストであれバイナリーであれ、ファイルの送受信に大差はない
もう一つ勉強になったのが、テキストもバイナリーも同じプログラムでレスポンスを返せるという点です。
上のgifで分かるよう、htmlやcssなどのテキストファイルだけでなくアイコンなどのバイナリファイルもレスポンスとして返していますが、両方とも全く同じ処理を行っています。
始端と終端が同じ小川に、泥水が流れてこようが原油が流れてこようが関係ない、意識する必要がないってことですね。
OSIの意味が何となく見えてきた気がする
OSIで言えば、小川の始端と終端を決めるのがネットワーク層で、小川で流れてきた中身を使って処理をするのがアプリケーション層、処理結果をユーザーさんに見せるのがプレゼンテーション層みたいな感じになるのかなと
今ならOSIの本が理解できる気がする...!!!