现在使用CoreBlueTooth L2CAP channel面临一些挑战。为了更好地理解事物是如何工作的。我从GitHub获取了L2CapDemo (master) (https://github.com/paulw11/L2CapDemo)并尝试使用它。以下是我所做的,以及一个问题。
在中已将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的情况下会发生什么。换句话说,所有字节都不能在一个块中发送。
现在问题来了。问题是我什么也没看到,剩下的字节似乎被忽略了。如果我不想忽略这些字节,我想知道该怎么做。关心其余字节的方法是什么?在某些情况下,我们将需要传输数万甚至数十万字节。
发布于 2019-09-02 15:53:34
您只需记下发送了多少个字符,从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分支中看到修改后的代码
https://stackoverflow.com/questions/57751590
复制相似问题