Android をHTTPサーバーにする

この記事は Shibuya.apk #22 でLTさせていただいた内容を、改めて文章としてまとめたものです。

当日は流れと勢いで英語で話してしまったということもあり、言いたいことが言えなかった部分もあったので、当日の発表の補足も兼ねてこの記事を公開できればと思います。

なお、発表資料は以下にアップロードしてあります。

[Can android be an http server? - SlideShare](https://www.slideshare.net/ssuserfe7d33/can-android-be-an-http-server-87315014)

# 本文

## はじめに
通常、Android端末を利用して通信する、というと、ユーザーのAndroid端末をクライアントとして、アプリ提供者の管理するサーバー用のマシンをサーバーとしてデータのやりとりを行う、ということが多いと思います。

この資料では、それとは反対に__AndroidをHTTPサーバーとして、PCをクライアントとして通信する__ことができるか、という問いに対する答えを紹介しています。

## TCPによるソケット通信
僕は現在、とあるメーカー企業で、組み込みAndroidデバイス（詳細はリリース前なので書けませんが）向けのアプリケーションに、__Android端末をサーバーとして、PCからデータを送信する__という仕組みを実装しています。

ユーザーが業務で利用しているPCからローカルネットワークで繋がっているこの端末（分かりやすい例では同じWiFiに繋がっている別の端末）へデータを送ることによって、リモートでこの端末を操作する、という使い方です。この仕組みはTCPを利用したソケット通信で実現しています。

あまり詳しくはないので表現が正確かどうかはわかりませんが、TCPはOSが提供する機能です。そして、我々が普段扱うWindowsやMac OS、そしてAndroid OSを含めたLinuxは、標準でTCPによる他の端末との通信ができるようになっています。つまり、TCPによるソケット通信を利用することで、Android端末はクライアントにもサーバーにもなれる、というワケです。

## HTTPとは
HTTPはTCPを元に仕様が決められています。別の言い方をすると、__TCPによるクライアント・サーバー間の、通信タイミングやデータ形式などのコミュニケーションの方式を定めたのがHTTP__だと言えます。また、その方式を定めるのが主に[RFC7230](https://tools.ietf.org/html/rfc7230)です。

つまり、TCPによる通信が可能であるということは、HTTPによる通信も（RFCの内容を実装すれば）可能である、ということになります。

## デモ
今回はそれを実験するために、デモアプリを作ってみました。

コードは以下のGitHubリポジトリにアップロードしてあります。

[AndroidHttpServerDemo - chooyan-eng](https://github.com/chooyan-eng/AndroidHttpServerDemo)

このデモは、[java.net.ServerSocket](https://docs.oracle.com/javase/9/docs/api/java/net/ServerSocket.html)クラスを利用して実装したTCPサーバーのデータの送受信をベースに、HTTPサーバーとしての振る舞いを簡単に実装したものです。

アプリを実行すると、中で先ほどのTCPサーバーが接続待ちを開始し、クライアント（このデモではWebブラウザ）からの接続の確立と、データの受信を行います。

受信したデータはHTTPで定められているフォーマットにしたがってパースされ、その結果読み取れたパスにしたがって返却するHTMLファイルを切り替えます。HTMLファイルはassetsフォルダにそのまま入っています。

返却する際もHTTPの定めるフォーマットにしたがってデータを整形することで、クライアント（Webブラウザ）は無事返却されたデータがHTMLファイルであることを認識し、ページを表示します。

最後に、アプリを停止させることで、ブラウザからそのURLにアクセスすることができなくなります。

なお、一連の流れはYoutubeにも動画を公開しています。
手元ですぐに確認できない場合は、こちらをご覧ください。

[[Demo] Can Android be an HTTP Server? - Youtube](https://www.youtube.com/embed/_hZ_UsFKnIU)

## どんなところで使えるか

さて、この技術について話す上で一番考えなければならないのが、__それはどんなときに使えるのか？__です。

普通に考えると、この仕組みをユーザー向けアプリとして提供することはあまり現実的ではありません。これを利用するには、__Androidが家のWiFiに固定で繋げられていて、Android以外にも何かデバイスがあって、なんらかの理由でAndroid自身に対してデータを送りつけたい（もしくはAndroidからデータを配信したい）__という状況が必要になるからです。

そこで思いついたのは、この発表の最初に説明した僕の職場のような、特定の業務向けの、特定のAndroid搭載端末[^1]を、PCやモバイル端末など手元にある任意のデバイスから操作する場合です。

Android端末へHTTPリクエストを送れることで、クライアントとなるPCや他のモバイル端末のブラウザやHTTPクライアントライブラリからそのAndroid端末を操作することができるようになる他、サーバーとなるAndroidの画面とタッチパネルを利用することでそのサーバーの状態やストアしたデータを手軽に確認できるのではないかと思います。

Android OSを搭載した端末自体に何か業務上の役割があり、それを複数人が好きなデバイスからアクセスしたい、という場合にこのアイデアが使えそうです。

## まとめ

AndroidはTCPが使え、TCPサーバーになれればHTTPサーバーにもなれるということをこの発表で紹介させていただきました。

これからAndroid Thingsへの注目が高まる中、__Androidをサーバーにする__というアイデアはどこかで何かに応用できるのではないかと思いました。以上です。

# LTの振り返り

というわけで、当日の発表では説明しきれなかった内容をこの記事にまとめてみました。
最初は「ソケット通信でしょ？知ってる知ってる」「で、それがどうしたの？」的な反応をされるのではないかとドキドキしながらのLTでしたが、割と反応がよくてホッとしました。

とはいえまだまだHTTPについて勉強が足りていないところだらけですので、引き続き勉強して行きたいと思います。きっと何かの役にたつはず。

なお、この発表の基になった試みとして、以下のようなものがあります。ついでに紹介しておきたいと思います。

* [Understand the basic idea of HTTP based on TCP - dev.to](https://dev.to/chooyan/understand-the-basic-idea-of-http-based-on-tcp-3i5j)
* [【TCP/IP】勉強がてらHTTPクライアントもどきをPythonで作ってみる - Qiita](https://qiita.com/chooyan_eng/items/087d2fd20294ed35e550)

[^1]: LTのあとで、「つまりそれはAndroid Thingsの出番だね！」と、DroidKaigi2018でAndroid Thingsのハンズオンをされるという方（名前聞きそびれました、、、）からお声がけいただきました