LoginSignup
1
2

More than 3 years have passed since last update.

iOS 端末で Let's ソケットプログラミング!

Last updated at Posted at 2021-02-05

ネットワークの基礎となる TCP/IP を理解するために、私はソケットプログラミングによる試行錯誤(Trial and Error)とネットワークトレースのパケット解析を避けては通れないと思っています。

本稿では、ソケットプログラミングをシミュレートする iOS アプリ SocTest を紹介します。

SocTest とは

Developer site より抜粋:

SocTest は、カーネルに対してシステムコールを発行し、インターネットや組織内のイントラネット上の様々なサーバーとソケット通信を行うモバイルアプリです。
SocTest のネットワーク操作は POSIX C API で実装されています。高度に抽象化された API を挟まず、必要以上にエラー判定せず、可能なかぎりカーネルに処理を委ねるように設計されています。

アプリは、App Store で無料で公開されています。

SocTest の使い方

具体例として、Wi-Fi 接続した状態で Safari ブラウザで ifconfig.io へアクセスする操作をシミュレートしてみます。

[参考]
ifconfig.io とは、接続元 IP アドレスを返してくれる WEB サービスです。
QiitaImage.001.jpeg

この場合、Safari で http://ifconfig.io/ip にアクセスすると、ifconfig.io が接続元であるグローバル IP アドレス「106.171.xx.97」を返します。
safari.jpeg

使用例①

Safari で実施しているソケット操作は、図に示したシステムコールを順番に発行していると考えられます。
QiitaImage.002.jpeg

では、SocTest アプリを起動して実際にシミュレートしてみます。

1-1. (事前準備) Address タブで ifconfig.io のアドレスを作成します

simulate1.001.jpeg

1-2. (事前準備) Data タブで HTTP リクエストのデータをバイナリエディタで作成します

simulate1.002.jpeg

HTTP の規約で、末尾は改行コード CRLF が2つ連続している必要があります。

リクエストデータ
GET /ip HTTP/1.1
Host: ifconfig.io
User-Agent: Mozilla/5.0 (SocTest; iOS 14.4)

1-3. Socket タブでソケットを作成し、ifconfig.io に接続します

simulate1.003.jpeg

1-4. HTTP リクエストを送信します

simulate1.004.jpeg

1-5. HTTP レスポンスを受信します

simulate1.005.jpeg

レスポンスデータ
HTTP/1.1 200 OK
Date: Fri, 05 Feb 2021 07:08:28 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 14
Connection: keep-alive
Set-Cookie: __cfduid=d526f31d8fba79e413589646c00846ad81612505125; expires=Sun, 07-Mar-21 07:08:28 GMT; path=/; domain=.ifconfig.io; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
cf-request-id: 0811f0af920000f8a7b5a18000000001
Report-To: {"max_age":604800,"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=dRvaw9S5bWhoae65VS1Spu6gT0I7LC4gdroUsse1iHMn%2By5yKxRkaJFyT%2F8zspLQP4sG64nvciiLQstZ15ILuG0bs204eSI5A%3D%3D"}],"group":"cf-nel"}
NEL: {"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 61c9b6f8efcaf8a7-NRT
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400

106.171.xx.97

Safari と同様の結果「106.171.xx.97」が得られたことが確認できましたね。

1-6. (後始末) ソケットをクローズします

simulate1.006.jpeg

1-7. (おまけ) ソケットシステムコールの発行内容を確認します

SocTest には、Linux の strace 相当のシステムコールトレース機能が搭載されています。
上記手順でどのようなシステムコールが発行されたのか確認できます。
simulate1.007.jpeg

トレース内容
16:08:18.446 Feb 05, 2021 - Asia/Tokyo (current)
16:08:18.446 Start (pid:2674)
16:08:20.899 [0.000098] socket(PF_INET, SOCK_STREAM, 0) = 3
16:08:24.676 [0.017037] connect(3, {sin_family=AF_INET, sin_port=80, sin_addr="104.21.65.79"}, 16) = 0
16:08:28.611 [0.000234] send(3, "GET /ip HTTP/1.1."..., 84, 0) = 84
16:08:35.069 [0.000066] recv(3, "HTTP/1.1 200 OK.."..., 4096, 0) = 787
16:08:45.045 [0.000150] close(3) = 0

使用例②

iOS では、モバイル通信と Wi-Fi が同時に接続されている状態では、Wi-Fi が優先して使用されます。
今度は、この状態であえてモバイル通信側(4G回線)を使用して ifconfig.io にアクセスできるか試してみます。
QiitaImage.003.jpeg

では、SocTest アプリを起動して実際にシミュレートしてみます。

2-1. (任意) アプリの動作設定で AUTO MONITORING を有効化します

このパラメータを有効にすると、着信データの有無や接続状態を監視するモードで動作します。
今回は、このモードを使ってみます。
simulate2.001.jpeg

2-2. モバイル通信のインターフェース(自分自身)のアドレスを確認して、ソケットに割り当てます

simulate2.002.jpeg

[参考]
ここでは、未使用の 60000 という適当なポート番号を指定しました。
0 を指定すると接続(connect)時に、カーネルによって自動的に採番されます。

2-3. ソケットを接続し、HTTP リクエスト/レスポンスの送受信を行います

simulate2.003.jpeg

レスポンスデータ
HTTP/1.1 200 OK
Date: Fri, 05 Feb 2021 07:59:24 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 15
Connection: keep-alive
Set-Cookie: __cfduid=de405e0a328b95a506f1099afe86f66cc1612508698; expires=Sun, 07-Mar-21 07:59:24 GMT; path=/; domain=.ifconfig.io; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
cf-request-id: 08129b30e60000d635e4917000000001
Report-To: {"max_age":604800,"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=G%2FxZA%2FLfDXM9dmMBsjZvSZ81B2MvsomKic0bDswtuWFZ3SNKEkBIKrAModd2oaTqM2vG4GD35c%2Bbfw2%2BdzWTQet8s4Vk%2BeCS6V4SDA%3D%3D"}],"group":"cf-nel"}
NEL: {"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 61cac7c7d8aad635-NRT
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400

153.147.xx.155

ifconfig.io によって、モバイル通信のアドレス「153.147.xx.155」が返されました。
つまり、Wi-Fi ではなく、モバイル通信側のネットワークが使用されたことが確認できました。

さいごに

SocTest では、TCP / UDP(ICMP も対応予定)のソケットをサポートしています。
60 個のソケットオプションを使用でき、Keep-Alive や Broadcast などのテストもできたりします。
sendmsg/recvmsg システムコールにより制御メッセージを使用した細かな制御もできたりします。

ネットワークに興味がある方、「ソケットプログラミングは敷居が高い」と敬遠されている方は、SocTest でソケット通信を体験してみてください!

おわり。

1
2
0

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
1
2