ほぼ自分用のメモでごめんなさい。
はじめに
iOSで例えば簡易HTTPサーバとか作ろうとすると割に面倒っぽいです。私が知らないだけの可能性も高いのですが、NSなんちゃらでそれっぽいのを探すことが出来ませんでした。
そこでgithubとか漁ってみますと、いくつかありました。HTTPサーバとなるとswifterとかが良さげに見えます。で中見るとお馴染みのsocketなAPIでよしなにしている感じでした。あーじゃあライブラリ理解するのも面倒だし、自分でもやれるなーと思って組んでみた訳です。
ところがbindでエラー
最近xcode8とかiOS10、Swift3になった関係か、いろいろと怒られまくりました。多くはxcode様のお導きで勝手に直っていったのですが、以下のコードだけがどうにもエラーから先に進みません。コード自体はswifterのを見ながら組んだ感じなのです。
var addr = sockaddr_in(sin_len: UInt8(strideof(sockaddr_in)),
sin_family: UInt8(AF_INET),
sin_port: port.bigEndian,
sin_addr: in_addr(s_addr: in_addr_t(0)),
sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
let bindResult = withUnsafePointer(to: &addr) {
bind(socketFileDescriptor, UnsafePointer<sockaddr>($0),
socklen_t(MemoryLayout<sockaddr_in>.size))
}
上記のbindがこんな感じで怒られるのです。withMemoryReboundとかSwift初心者にはかなり厳しそう(滝汗)
'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.
これでOK
socket系になると私のスキルではAppleDevelopperサイトから情報を引き出すのは難しかったです(お恥ずかしい話です)。
で、答えはstackoverflowにありました。どうもポインタ系の修正が必要になるみたいです。つまりはエラーメッセージの通りではあるのですが…。stackoverflowに従って以下のように記載することでパスりました(一応Xcodeに言われたような方法でなおしてみました)
var addr = sockaddr_in(sin_len: UInt8(strideof(sockaddr_in)),
sin_family: UInt8(AF_INET),
sin_port: port.bigEndian,
sin_addr: in_addr(s_addr: in_addr_t(0)),
sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
let bindResult = withUnsafePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(socketFileDescriptor, $0,
socklen_t(MemoryLayout<sockaddr_in>.stride))
}
}
bind以外はそれほど大したこともなく、シミュレータレベルですが、bindした後accept出来ることをiPhone7/iOS10で確認できました。いやーSwiftでメモリ操作なんて、C++で「;」をしょっちゅう忘れてしまう私にはハードルが高い高い(なぜか涙が…)
ただこれ、swifterとか大丈夫なのかなーとは思いました。
おわりに
stackoverlow様には(いつもではありますが)もう感謝です。
(一応)上記のコードはパブリックドメインとします。当然ですが使用した際の損害は誰も請け負ってくれません。そこだけ注意願います。
以上です。