0
2

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 3 years have passed since last update.

iOS の Network FrameworkでUDPクライアントの受信処理を実装したら、「udp_validate_cksum_internal udp incorrect IPv4-UDP offload checksum」というエラーが出た

Last updated at Posted at 2021-03-23

Problem

iOSのNetwork Frameworkを使ってUDPクライアントの受信処理を実装したところ、UDP通信ができず以下のようなエラーが表示されることがありました。

udp_validate_cksum_internal  udp incorrect IPv4-UDP offload checksum 0xf6dc ulen 1154
udp_validate_cksum_internal  udp incorrect IPv4-UDP offload checksum 0xf5dd ulen 1154
udp_validate_cksum_internal  udp incorrect IPv4-UDP offload checksum 0xf5dd ulen 1154

エラーメッセージで検索すると、同じエラーに遭遇した人もいたのですが、解決策は書いてありませんでした。
https://developer.apple.com/forums/thread/665536

参考までにNetwork Frameworkを使った実装を載せます。(一部省略)

UdpClientImplNW.swift

import Foundation
import Network

/// Network Frameworkを使って実装したバージョン
class UdpClientImplNW {
    private var nwListener: NWListener!
    private let queue = DispatchQueue(label: "UdpClient")

    func bind(port: Int32) {
        let nwPort = NWEndpoint.Port(rawValue: UInt16(port))!
        let params = NWParameters.udp
        params.allowLocalEndpointReuse = true
        let listener = try! NWListener(using: params, on: nwPort)
        nwListener = listener
        listener.stateUpdateHandler = stateDidChange(to:)
        listener.newConnectionHandler = { [unowned self] (connection: NWConnection) in
            connection.start(queue: queue)
            self.receive(on: connection)
        }
        nwListener.start(queue: queue)
    }

    private func stateDidChange(to newState: NWListener.State) {
        print("NWListener stateDidChange: \(newState)")
    }

    private func receive(on connection: NWConnection) {
        connection.receiveMessage(completion: {(data, context, isComplete, error) in
            if let error = error {
                // エラー発生時の処理
            }
            if let data = data {
                // データ受信時の処理
            }

            // 連続して受信する
            self.receive(on: connection)
        })
    }
}

Solution

恐らく、Network Frameworkのバグと思われるため、robbiehanson/CocoaAsyncSocketというライブラリを使って書き直しました。
そうすると、正常にUDPの受信ができ、エラーメッセージも表示されませんでした。

以下がCocoaAsyncSocketを使った実装です。(一部省略)

UdpClientImpl.swift
import Foundation
import CocoaAsyncSocket

class UdpClientImpl: NSObject {
    private var socket: GCDAsyncUdpSocket!
    private var port: UInt16!

    func bind(port: Int) {
        self.port = UInt16(port)
        socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
        do {
            try socket.enableReusePort(true)
        } catch {
            print("Failed to setup socket: \(error)")
        }
        
        do {
            try socket.bind(toPort: UInt16(port))
            try socket.beginReceiving()
        } catch {
            print("Failed to receive: \(error)")
        }
    }
}

extension UdpClientImpl: GCDAsyncUdpSocketDelegate {
    func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
        // データ受信時の処理
    }

    func udpSocket(_ sock: GCDAsyncUdpSocket, didNotConnect error: Error?) {
        // 接続失敗時の処理
    }

    func udpSocketDidClose(_ sock: GCDAsyncUdpSocket, withError error: Error?) {
        // エラー発生時の処理
    }
}
0
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?