32
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Swift3.0】【Xcode8】【iOS10】 Swift3でなんちゃってHTTPサーバを作ってみました。

Posted at

iOSでコードを組む場合、クライアントなんかは充実しているように感じます。例えばRESTFulをするHTTPクライアントはサービスペペっと呼べばまぁ良い感じに出来ます。が、サーバはそうもいかない印象があります。まぁ普段使わないし、いろいろ面倒事もありますので・・

更にSwift3になって、サーバ系のライブラリが色々使えなかったりとかしたり(ただ最近は是正されつつあります)。

例えばお外でBLEなデバイスのデータを受信解析とかして、その結果を別なノーパソから取る場合、サーバにした方がむしろ楽な時があります。サーバにしといて、状況をcurlで引っ張ってRで可視化とか、簡単な統計をHTMLにしてブラウザで見たりとかです。個人的には回線とBLEも使える実験用データサーバとしてスマホ(私の場合はiPhone)は優れものだと思います。

そういう事を行うためのHTTPサーバっぽいプログラムを作ってみました。

で、何ができるの?

なんちゃってHTTPサーバもどきとして、以下の事しかできません。

  • プログラムで生成されたHTMLを表示
  • バンドルされたファイルを転送
  • プログラムで生成したDocumentファイルを転送
  • IPv4でのみ動作します。

上記を実現するため、以下の機能をもっています。

  • ファイルの読み書き
  • バンドルされたファイルのパス取得
  • プログラムで書いてDocumentに入れたファイルのパスを取得
  • ファイルアクセス関連で使う UInt8配列とかNSData関係のオブジェクト変換
  • 同じくStringと上記オブジェクトとの変換
  • 通信と連動してView系を更新する
  • socketを使った通信(TCPサーバ)

iOSに慣れた方にとっては、socketを除き上記はしょーもない機能なのかもしれません。が、普段やってない人にとってはSwift3の変更もあって、ハードル高いです。そういう機能もAPIにしてみましたので、慣れない方の参考になると・・・いいな。

TCPサーバを実現するコード

具体的にどう実現したかは、GitHubにxcodeのプロジェクトを入れましたので、そのコードを見てもらった方が早いです。gdSampleServerフォルダにあるswift達の内訳を書きます。

URL
https://github.com/gdaigo82/iosSampleServer

ファイル名 内容
ViewController.swift main的な処理。UIの配置など
TinyHTTPServer.swift 以下を利用したHTTPサーバ処理
SimpleTCPServer.swift socketを使ったTCPサーバ
SimpleFileService.swift ファイルアクセス関係
SimpleCharacter.swift 画像とかテキストの表示を担当
ToolSample.swift UInt8、NSData、のオブジェクト交換、時刻・IP取得など雑多なツール

私同様、慣れていない方が何らかの参考にしていただくとか、利用していただければ幸いです。

ちなみにTinyHTTPServer.swiftを見てもらうと分かりますが、HTTPとしてはかなりナメた実装なので、あくまでも参考として下さい(苦笑)

評価方法

動かして戴ける方のために、簡単に動かし方を説明します。まずはgitから落とすかzipを解凍します。

URL
https://github.com/gdaigo82/iosSampleServer

次に適当なJPEG画像をsample.jpgとして用意し、それをgdSampleServer/gdSampleServerフォルダに入れます。

その後、xcodeでビルドし、実機もしくはiOSシミュレータで起動してください。例によってですがプロ生ちゃんが出てきます。

ios_server_1.PNG

#ちなみに実機ですと、本当は3G回線のIPも出ます(つまり2行表示されます)。上の図では一応消させていただきました。

このように生IPでURLが表示されます。またこのアプリは縦固定としています。で、実際にはLAN内のIPを使う事になるかと思います(図だと10.0.0.4)。LAN内のブラウザからまずはそのまま(図なら 10.0.0.4:8081 )打ち込むと、ブラウザに時刻が表示され、iOS上の画面も変化します。

■ブラウザ
ios_server_html.PNG

■iOS側
ios_server_2.PNG

この他にも、画像を出したり、あるいはログ(転送サイズ)を出したりできます。URLはそれぞれ /img と /log です。例えばIPが10.0.0.4ならば以下のURLに対応しています。ポート番号はハードコーディングしてますので、必要ならSwiftいじって修正していただければ。

  • 10.0.0.4:8081/img で画像
  • 10.0.0.4:8081/log でログ(総転送サイズ)
  • 10.0.0.4:8081 でHTML(時刻)-というか上2つ以外すべてこれ。

また、プロ生ちゃんをクリックしますと初期画面に戻りますので、IPの再確認とかできます。

という事で、一応Webブラウザでデータが拾えているのが分かるかと思います。

TIPS

コードを組みにあたり、ひっかかったトコなどをまとめておきます。

IP取得

いつものstack overflowさんです。以下を参考というかほぼ丸々使わせて戴きました(IPv6は使わないようにしたぐらいですね)

socket系をswiftで実現するためのxcode8の操作

特殊なヘッダをプロジェクトに追加する必要があります。以下が参考になりました。但しパスは少し工夫してます(プロジェクトフォルダをこれは直接指定しました)

bind系

手前味噌で恐縮ですが・・

時刻取得

手前味噌で恐縮ですが2

マルチスレッド処理とUIとの連携

一般にGUIを持つシステムでマルチスレッドやると、Viewを管轄するスレッド以外からのUIアクセスについて、気にかける必要があります。iOSもそうです。以下、TinyHTTPServer.swiftから該当処理を抜粋してみました。とりあえずこれで動くようです。

    // UIと別スレッドをこんな感じで処理させてみました。
    // 
    func mainFunc(label : String) {
        let queue = DispatchQueue(label: label)
        queue.async { // ここでViewControlerのスレッドから切り離します。
            self.serverMainSequence() // HTTPサーバのメイン処理(connectからrecv,sendしてshutdownまで)
            DispatchQueue.main.async { // ここでViewControlerのスレッドに戻ることを期待
                // 戻ったので、viewに対していろいろやらかします。
                var text = (self.tool?.getNowClockString())!
                text += " " + self.count.description + "回目\n"
                text += self.serif!
                self.character?.reaction(serif: text, image: self.image!) // これが表示処理です。
                self.count += 1
                self.mainFunc(label: "gdaigo82.server") // 最後に自分を呼び出します。
            }
        }
    }

これ、本来は以下のように処理したいのです。

while (true)
{
    self.serverMainSequence() // HTTPサーバのメイン処理(connectからrecv,sendしてshutdownまで)
    self.character?.reaction(serif: text, image: self.image!)  // これが表示処理です。
}

ただ、実際HTTP系は別スレッドで処理させたかったので、DispatchQueueを使ってみました。どうもqueue.async {}とすると、{}の中は別スレッドになるみたいです。更にその中でDispatchQueue.main.async {} と書くと、その上の処理が終わった際にmainつまりUIを担当するスレッドに切り替えてくれ、結果 {}の中ではUIが操作可能になるっぽいです。

なので、通信系とUI表示を連動させたければ、このような書き方をすれば出来るみたいです。

本件、以下が大変参考になりました。

ライセンス

以下使わせて戴きました。素晴らしいソフトウェアを提供して下さり、ありがとうございます。

以上です。

32
34
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?