Опитвам се да разбера L2CAP канала

Сега се сблъсква с някои предизвикателства, използвайки CoreBlueTooth L2CAP channel. За да разберете по-добре как работят нещата. Взех L2CapDemo (главен) (https://github.com/paulw11/L2CapDemo) от GitHub и се опита да експериментира с него. Ето какво направих, заедно с един въпрос.

Заменихме функцията sendTextTapped с тази:

@IBAction func sendTextTapped(_ sender: UIButton) {
    guard let ostream = self.channel?.outputStream else {
        return
    }

    var lngStr = "1234567890"
    for _ in 1...10 {lngStr = lngStr + lngStr}
    let data = lngStr.data(using: .utf8)!

    let bytesWritten =  data.withUnsafeBytes { ostream.write($0, maxLength: data.count) }
    print("bytesWritten = \(bytesWritten)")
    print("WR = \(bytesWritten) / \(data.count)")
}

И резултатът от изпълнението е:

bytesWritten = 8192
WR = 8192 / 10240

Това ми позволява да видя какво се случва в случай, когато bytesWritten ‹ data.count. С други думи, всички байтове не могат да бъдат изпратени в една част.

Сега идва въпросът. Проблемът е, че не виждам нищо, останалите байтове изглежда просто се игнорират. Искам да знам какво да правя, ако не искам да игнорирам тези байтове. Какъв е начинът да се грижим за останалите байтове? Ще има случаи, в които ще трябва да прехвърлим десетки хиляди или дори стотици хиляди байтове.


person Michel    schedule 02.09.2019    source източник


Отговори (1)


Просто трябва да отбележите колко знака са изпратени, да ги премахнете от екземпляра data и след това, когато получите обратно извикване на делегат, което показва, че има свободно място в изходния поток, изпратете още.

Например, можете да добавите няколко свойства за задържане на данните в опашката и опашка за серийно изпращане, за да осигурите безопасен достъп до тази опашка:

private var queueQueue = DispatchQueue(label: "queue queue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem, target: nil)

private var outputData = Data()

Сега във функцията sendTextTapped можете просто да добавите новите данни към изходната опашка:

@IBAction func sendTextTapped(_ sender: UIButton) {     
    var lngStr = "1234567890"
    for _ in 1...10 {lngStr = lngStr + lngStr}
    let data = lngStr.data(using: .utf8)!

    self.queue(data:data)  
}

функцията queue(data:) добавя данните към обекта outputData по безопасен за нишката начин и извиква send()

private func queue(data: Data) {
    queueQueue.sync  {
        self.outputData.append(data)
    }
    self.send()   
}

send() гарантира, че потокът е свързан, има данни за изпращане и има свободно място в изходния поток. Ако всичко е наред, тогава той изпраща толкова байтове, колкото може. След това изпратените байтове се премахват от изхода data (отново по безопасен начин).

private func send() {

    guard let ostream = self.channel?.outputStream, !self.outputData.isEmpty, ostream.hasSpaceAvailable  else{
        return
    }
    let bytesWritten =  outputData.withUnsafeBytes { ostream.write($0, maxLength: self.outputData.count) }
    print("bytesWritten = \(bytesWritten)")
    queueQueue.sync {
        if bytesWritten < outputData.count {
            outputData = outputData.advanced(by: bytesWritten)
        } else {
            outputData.removeAll()
        }
    }
}

Последната промяна е да се извика send() в отговор на .hasSpaceAvailable поточно събитие:

func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    switch eventCode {
    case Stream.Event.openCompleted:
        print("Stream is open")
    case Stream.Event.endEncountered:
        print("End Encountered")
    case Stream.Event.hasBytesAvailable:
        print("Bytes are available")
    case Stream.Event.hasSpaceAvailable:
        print("Space is available")
        self.send()
    case Stream.Event.errorOccurred:
        print("Stream error")
    default:
        print("Unknown stream event")
    }
}

Можете да видите модифицирания код в largedata клон на примера

person Paulw11    schedule 02.09.2019
comment
Добре честно. След това трябва да се работи на ръка. Алгоритмичната част от това е доста лесна, но просто си помислих, че може да има някаква обработка, обработена автоматично, за която не знаех. Благодаря, че изясни това. Освен това, тъй като в крайна сметка се интересувам от прехвърляне на двоични данни (а не само низове), по-късно ще трябва да видя как да премахна байтове (и да ги добавя от приемащата страна) от обект с данни (за който все още не съм сигурен правилният синтаксис за използване). - person Michel; 02.09.2019
comment
Кодът по-горе ще изпрати всякакви данни; Няма нищо специално за двоичните данни срещу низовете. Това, което трябва да обмислите, е рамкирането - откъде знаете, че това е началото на файл в потока и това е краят' - Вероятно трябва да изпратите някакъв вид заглавка, - person Paulw11; 02.09.2019
comment
ДОБРЕ. Страхотно, ще отделя известно време, за да разгледам това. - person Michel; 02.09.2019