InputStream从不调用hasBytesAvailable

时间:2018-02-17 20:26:18

标签: networking swift4 bonjour nsinputstream nsoutputstream

我正在尝试让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)
        }
    }
}

0 个答案:

没有答案