我正在尝试让iOS设备通过Bonjour发现彼此,然后使用InputStream和OutputStream进行连接。
设备可以相互连接,但是从一个设备的OutputStream发送字节不会在另一个设备上触发“hasBytesAvailable”事件。
因为我希望设备与多个其他设备连接,所以我将每个连接都包装在一个“ASPeer”对象中,我可以将其放入一个数组中以跟踪我的所有连接。
class ASPeer: NSObject {
let service: NetService
var inputStream: InputStream?
var outputStream: OutputStream?
init(_ service: NetService) {
self.service = service
}
func openStreams() {
guard let inputStream = inputStream, let outputStream = outputStream else {
fatalError("openStreams: failed to get streams!")
}
inputStream.delegate = self
inputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
inputStream.open()
outputStream.delegate = self
outputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
outputStream.open()
}
func closeStreams() {
guard let inputStream = inputStream, let outputStream = outputStream else {
fatalError("closeStreams: failed to get streams!")
}
inputStream.remove(from: .current, forMode: .defaultRunLoopMode)
inputStream.close()
inputStream.delegate = nil
outputStream.remove(from: .current, forMode: .defaultRunLoopMode)
outputStream.close()
outputStream.delegate = nil
}
}
extension ASPeer: StreamDelegate {
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch aStream {
case inputStream!:
switch eventCode {
case .openCompleted:
print("inputOpenCompleted:")
case .hasBytesAvailable:
print("inputHasBytesAvailable:")
var readData = [UInt8](Data(capacity: 4096))
let bytesRead = inputStream!.read(&readData, maxLength: 4096)
if bytesRead > 0 {
print(String(bytes: readData, encoding: .ascii)!)
}
case .errorOccurred:
print("inputErrorOccurred")
case .endEncountered:
print("inputEndEncountered")
default:
break
}
case outputStream!:
switch eventCode {
case .openCompleted:
print("outputOpenCompleted:")
case .hasSpaceAvailable:
print("outputHasSpaceAvailable:")
case .errorOccurred:
print("outputErrorOccurred")
case .endEncountered:
print("outputEndEncountered")
default:
break
}
default:
print("got unknown stream!")
}
}
}
我为输入和输出流的每个“handle”事件添加了print语句。以下是运行应用程序并尝试让设备相互通信时的输出日志:
Device 1
inputOpenCompleted:
outputOpenCompleted:
outputHasSpaceAvailable:
Device 2
inputOpenCompleted:
outputOpenCompleted:
outputHasSpaceAvailable:
当我尝试从设备1向设备2发送消息时,我希望设备2打印出“inputHasBytesAvailable”。但是,我只是从设备1获得额外的“outputHasSpaceAvailable”行:
Device 1
inputOpenCompleted:
outputOpenCompleted:
outputHasSpaceAvailable:
outputHasSpaceAvailable: <--
outputHasSpaceAvailable: <--
Device 2
inputOpenCompleted:
outputOpenCompleted:
outputHasSpaceAvailable:
<-- I'm expecting "inputHasBytesAvailable" here!
问题是什么?我已经仔细检查了我的运行循环,并确保它们是正确的。此外,似乎有一个“getInputStream”的错误,我确保在主队列上调用“getInputStream”以避免这个问题。还有其他我想念的东西吗?
此外,我还有一个BonjourManager对象来管理这些“ASPeer”连接中的每一个。 BonjourManager实际上是创建连接并将写入发送到OutputStreams。
class ASBonjourManager: NetServiceDelegate {
var peers = [ASPeer]()
// ... more code here but omitted
func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream: OutputStream) {
if sender == advertiser {
return
}
if let peer = peers.first(where: { $0.service == sender }) {
OperationQueue.main.addOperation {
// Due to a bug <rdar://problem/15626440>, this method is called on some unspecified
// queue rather than the queue associated with the net service (which in this case
// is the main queue). Work around this by bouncing to the main queue.
assert((peer.inputStream == nil) == (peer.outputStream == nil))
if let _ = peer.inputStream, let _ = peer.outputStream {
inputStream.open()
inputStream.close()
outputStream.open()
outputStream.close()
} else {
peer.inputStream = inputStream
peer.outputStream = outputStream
peer.openStreams()
}
}
} else {
OperationQueue.main.addOperation {
let newPeer = ASPeer(sender)
sender.delegate = self
newPeer.inputStream = inputStream
newPeer.outputStream = outputStream
newPeer.openStreams()
self.peers.append(newPeer)
}
}
}
func connectTo(service: NetService) {
var inStream: InputStream?
var outStream: OutputStream?
let peer = peers.first(where: { $0.service.isEqual(service) })!
//assert(peer.inputStream == nil && peer.outputStream == nil)
if peer.inputStream != nil && peer.outputStream != nil {
return
}
if service.getInputStream(&inStream, outputStream: &outStream) {
peer.inputStream = inStream
peer.outputStream = outStream
peer.openStreams()
} else {
print("getInputStream failed!")
}
}
func sendMessage(_ service: NetService) {
let peer = peers.first(where: { $0.service.isEqual(service) })!
if peer.outputStream!.hasSpaceAvailable {
let message = Array("hello world".utf8)
peer.outputStream!.write(message, maxLength: message.count)
}
}
}