はじめに
iOS16/macOS13からNetwork.frameworkがQUICのDatagramに対応しました
6分24秒〜あたりで触れられています
試しに、quic-goとDatagramでechoしてみました
iOS16とmacOS13で動作することを確認しました
実装
リポジトリはこちら
Client (Swift)
NWProtocolQUIC.Optionsを作成して、isDatagramを有効にし、maxDatagramFrameSizeを設定します
今回はローカルでテストしたのでオレオレ証明書でも信頼します
NWConnectionGroupを作成して、各種handerを登録してstartします
NWConnectionと違い、NWConnectionGroupはメッセージを受け取る度に、setReceiveHandlerを再帰的に設定する必要はないようです
let options = NWProtocolQUIC.Options(alpn: ["echo"])
options.direction = .bidirectional
options.isDatagram = true
options.maxDatagramFrameSize = 65535
let securityProtocolOptions: sec_protocol_options_t = options.securityProtocolOptions
sec_protocol_options_set_verify_block(securityProtocolOptions,
{ (_: sec_protocol_metadata_t,
_: sec_trust_t,
complete: @escaping sec_protocol_verify_complete_t) in
complete(true) // オレオレ証明書でも信頼する
}, DispatchQueue.main)
let params = NWParameters(quic: options)
let desc = NWMultiplexGroup(to: .hostPort(host: "xxx.xxx.xxx.xxx", port: 4433))
let group = NWConnectionGroup(with: desc, using: params)
group.setReceiveHandler { (message: NWConnectionGroup.Message,
content: Data?,
isComplete: Bool) in
print("receive message: \(message)")
print("receive content: \(String(describing: content))")
print("receive isComplete: \(isComplete)")
}
group.stateUpdateHandler = { (state: NWConnectionGroup.State) in
print("state: \(state)")
}
group.start(queue: queue)
メッセージを送信する際には、NWConnectionGroup.send(content: to:message:completion:)を利用します
group.send(content: "Hello".data(using: .utf8)!) { (error: Error?) in
print("send error: \(String(describing: error))")
}
Server (Go)
quic.Connectionが作成されるのを待って、受け取ったデータをそのまま返します
package main
import (
"context"
"crypto/tls"
"github.com/alta/insecure"
"github.com/quic-go/quic-go"
)
func main() {
cert, _ := insecure.Cert()
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
NextProtos: []string{"echo"},
}
quicConfig := &quic.Config{
EnableDatagrams: true,
}
listener, _ := quic.ListenAddr(":4433", tlsConfig, quicConfig)
for {
conn, _ := listener.Accept(context.Background())
go func(conn quic.Connection) {
for {
bytes, _ := conn.ReceiveMessage()
conn.SendMessage(bytes)
}
}(conn)
}
}
終わりに
Network.frameworkを利用することでシンプルに、iOS/macOSでもDatagramを利用できました
ただNetwork.frameworkもquic-goもドキュメントが若干少なく、QUICの予備知識が自分に無かったので、どちらが悪いのか、自分の実装が悪いのか分からず、困る場面もありました
↑結果的に、自分の実装が悪かったようですw
Appleが思いの外?QUICの実装に積極的な印象があるので、このままWebTransportまで実装してくれたら嬉しいななどと思っています
Network.frameworkのQUICのストリームについても書いてます!