Trying to understand L2CAP channel

点点圈 提交于 2020-01-16 08:49:07

问题


Now facing some challenges using CoreBlueTooth L2CAP channel. In order to better understand how things work. I have taken the L2CapDemo (master) (https://github.com/paulw11/L2CapDemo) from GitHub and tried to experiment with it. Here is what I have done, along with one question.

In have replaced the sendTextTapped function, with this one :

@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)")
}

And the execution result is:

bytesWritten = 8192
WR = 8192 / 10240

That allows me to see what happens in the case where bytesWritten < data.count. In other words, all the bytes cannot be sent over in one chunk.

Now comes the question. The problem is I see nothing, the bytes left over seems to be just ignored. I want to know what to do if I do not want to ignore those bytes. What is the way to care about the rest of the bytes? There will be cases where we will need to transfer tens of thousands or even hundreds of thousands of bytes.


回答1:


You simply need to make a note of how many characters were sent, remove those from the data instance and then when you get a delegate callback indicating space is available in the output stream, send some more.

For example, you could add a couple of properties to hold the queued data and a serial dispatch queue to ensure thread-safe access to that queue:

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

private var outputData = Data()

Now, in the sendTextTapped function you can just add the new data to the output queue:

@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)  
}

the queue(data:) function adds the data to the outputData object in a thread-safe manner and calls send()

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

send() ensures that the stream is connected, there is data to send and there is space available in the output stream. If all is OK then it sends as many bytes as it can. The sent bytes are then removed from output data (again in a thread safe manner).

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()
        }
    }
}

The final change is to call send() in response to a .hasSpaceAvailable stream event:

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")
    }
}

You can see the modified code in the largedata branch of the example



来源:https://stackoverflow.com/questions/57751590/trying-to-understand-l2cap-channel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!