Swift:读/写&;I/O流和URLSessionStreamTask的连接问题
上下文Swift:读/写&;I/O流和URLSessionStreamTask的连接问题,swift,io,bonjour,nsinputstream,nsoutputstream,Swift,Io,Bonjour,Nsinputstream,Nsoutputstream,上下文 我正在尝试创建一个基于Bonjour NetService和URLSessionStreamTask的通信通道来打开I/O流 我已经准备好了安装程序,我能够连接到bonjour服务并打开mac和iOS应用程序之间的I/O流 我在请求和响应中使用swift编码,所以通信基于编码为数据的可编码结构。我发送一个请求结构(通过outputStream.write(data))并在输入流中等待来自mac app的响应结构 问题 extension InputStream { private
- 我正在尝试创建一个基于Bonjour NetService和URLSessionStreamTask的通信通道来打开I/O流
- 我已经准备好了安装程序,我能够连接到bonjour服务并打开mac和iOS应用程序之间的I/O流
- 我在请求和响应中使用swift编码,所以通信基于编码为数据的可编码结构。我发送一个请求结构(通过
)并在输入流中等待来自mac app的响应结构outputStream.write(data)
extension InputStream {
private var maxLength: Int { return 4096 }
func read(data: inout Data) -> Int {
var totalReadCount: Int = 0
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxLength)
while hasBytesAvailable {
let numberOfBytesRead = read(buffer, maxLength: maxLength)
if numberOfBytesRead < 0, let error = streamError {
print("Read Error: \(error)")
break
}
data.append(buffer, count: numberOfBytesRead)
totalReadCount += numberOfBytesRead
}
return totalReadCount
}
}
extension OutputStream {
@discardableResult
func write(data: Data) -> Int {
if streamStatus != .open {
open()
}
let count = data.count
let result = data.withUnsafeBytes {
write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: count)
}
close()
return result
}
}
- 我正在发送
请求(在收到fetchUser
的响应后),mac app收到请求并写入响应,但没有logiuser
失败write
,但我没有在iOS app中收到响应。(尽管我收到了上一个(-1)
请求的响应)loginUser
- 我无法找出问题的确切位置,将代码片段附加到这里
- PS:我是IO streams处理方面的noob,所以详细的回复会很有帮助。也许有一些资料可以让我更了解这个话题
let service: NetService = NetService(domain: "local.", type: "_my-app._tcp.", name: "test", port: 0)
service.delegate = self
service.publish(options: .listenForConnections)
//Writes response to connected output stream
func send(response: HalloResponse) {
do {
let data = try encoder.encode(response)
print("HalloServer: Response: \(String(describing: String(data: data, encoding: .utf8)))")
if serviceDelegate.dataStream?.outputSteam.write(data: data) == -1 {
print("HalloServer: send(response: HalloResponse) Write failied")
}
} catch {
print("HalloServer: Exception in send(request: Request)")
}
}
//NetServiceDelegate
func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream: OutputStream) {
print("NetServiceDelegate: service - \(sender.name) inputStream - \(inputStream) outputStream \(outputStream)")
self.inputStream = inputStream
self.outputSteam = outputSteam
self.inputStream.delegate = self
self.outputSteam.delegate = self
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.open()
self.inputStream.open()
}
// StreamDelegate
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
print("StreamDelegate: handle eventCode: \(eventCode.rawValue)")
if inputStream == aStream {
switch eventCode {
case .hasBytesAvailable:
var data = Data()
guard inputStream.read(data: &data) > 0 else { return }
print("HalloDataStream: Recieved data - \(String(describing: String(data: data, encoding: .utf8)))")
let decoder = JSONDecoder()
if let request = try? decoder.decode(Request.self, from: data) {
delegate?.didReceive(request: request)
}
if let response = try? decoder.decode(HalloResponse.self, from: data) {
delegate?.didReceive(response: response)
}
default: break
}
}
}
serviceBrowser.searchForServices(ofType: "_my-app._tcp.", inDomain: "local.")
func connect(with service: NetService, completion: @escaping DeviceConnectionCompletion) {
deviceCompletion = completion
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: config, delegate: self, delegateQueue: .main)
streamTask = session.streamTask(with: service)
streamTask?.resume()
streamTask?.captureStreams()
}
func send(request: Request) {
do {
let data = try encoder.encode(request)
print("HalloClient: Request: \(String(describing: String(data: data, encoding: .utf8)))")
if dataStream?.outputSteam.write(data: data) == -1 {
print("HalloClient: send(request: Request) Write failied")
}
} catch {
print("HalloClient: Exception in send(request: Request)")
}
}
// URLSessionStreamDelegate
func urlSession(
_ session: URLSession,
streamTask: URLSessionStreamTask,
didBecome inputStream: InputStream,
outputStream: OutputStream
) {
print("didBecomeInputStream:(NSInputStream *)inputStream outputStream: OutputStream")
deviceCompletion?(true)
self.inputStream = inputStream
self.outputSteam = outputSteam
self.inputStream.delegate = self
self.outputSteam.delegate = self
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.open()
self.inputStream.open()
}
// StreamDelegate
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
// code exactly same as mac app delegate
}
iOS应用程序代码
let service: NetService = NetService(domain: "local.", type: "_my-app._tcp.", name: "test", port: 0)
service.delegate = self
service.publish(options: .listenForConnections)
//Writes response to connected output stream
func send(response: HalloResponse) {
do {
let data = try encoder.encode(response)
print("HalloServer: Response: \(String(describing: String(data: data, encoding: .utf8)))")
if serviceDelegate.dataStream?.outputSteam.write(data: data) == -1 {
print("HalloServer: send(response: HalloResponse) Write failied")
}
} catch {
print("HalloServer: Exception in send(request: Request)")
}
}
//NetServiceDelegate
func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream: OutputStream) {
print("NetServiceDelegate: service - \(sender.name) inputStream - \(inputStream) outputStream \(outputStream)")
self.inputStream = inputStream
self.outputSteam = outputSteam
self.inputStream.delegate = self
self.outputSteam.delegate = self
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.open()
self.inputStream.open()
}
// StreamDelegate
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
print("StreamDelegate: handle eventCode: \(eventCode.rawValue)")
if inputStream == aStream {
switch eventCode {
case .hasBytesAvailable:
var data = Data()
guard inputStream.read(data: &data) > 0 else { return }
print("HalloDataStream: Recieved data - \(String(describing: String(data: data, encoding: .utf8)))")
let decoder = JSONDecoder()
if let request = try? decoder.decode(Request.self, from: data) {
delegate?.didReceive(request: request)
}
if let response = try? decoder.decode(HalloResponse.self, from: data) {
delegate?.didReceive(response: response)
}
default: break
}
}
}
serviceBrowser.searchForServices(ofType: "_my-app._tcp.", inDomain: "local.")
func connect(with service: NetService, completion: @escaping DeviceConnectionCompletion) {
deviceCompletion = completion
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: config, delegate: self, delegateQueue: .main)
streamTask = session.streamTask(with: service)
streamTask?.resume()
streamTask?.captureStreams()
}
func send(request: Request) {
do {
let data = try encoder.encode(request)
print("HalloClient: Request: \(String(describing: String(data: data, encoding: .utf8)))")
if dataStream?.outputSteam.write(data: data) == -1 {
print("HalloClient: send(request: Request) Write failied")
}
} catch {
print("HalloClient: Exception in send(request: Request)")
}
}
// URLSessionStreamDelegate
func urlSession(
_ session: URLSession,
streamTask: URLSessionStreamTask,
didBecome inputStream: InputStream,
outputStream: OutputStream
) {
print("didBecomeInputStream:(NSInputStream *)inputStream outputStream: OutputStream")
deviceCompletion?(true)
self.inputStream = inputStream
self.outputSteam = outputSteam
self.inputStream.delegate = self
self.outputSteam.delegate = self
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.schedule(in: .main, forMode: .default)
self.inputStream.open()
self.inputStream.open()
}
// StreamDelegate
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
// code exactly same as mac app delegate
}
IO流上的扩展
extension InputStream {
private var maxLength: Int { return 4096 }
func read(data: inout Data) -> Int {
var totalReadCount: Int = 0
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxLength)
while hasBytesAvailable {
let numberOfBytesRead = read(buffer, maxLength: maxLength)
if numberOfBytesRead < 0, let error = streamError {
print("Read Error: \(error)")
break
}
data.append(buffer, count: numberOfBytesRead)
totalReadCount += numberOfBytesRead
}
return totalReadCount
}
}
extension OutputStream {
@discardableResult
func write(data: Data) -> Int {
if streamStatus != .open {
open()
}
let count = data.count
let result = data.withUnsafeBytes {
write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: count)
}
close()
return result
}
}
扩展输入流{
私有变量maxLength:Int{return 4096}
func read(数据:输入输出数据)->Int{
变量totalReadCount:Int=0
let buffer=unsafemeutablepointer.allocate(容量:maxLength)
当Hasbytes可用时{
让numberOfBytesRead=read(缓冲区,maxLength:maxLength)
如果numberOfBytesRead<0,则让错误=拖缆错误{
打印(“读取错误:\(错误)”)
打破
}
data.append(缓冲区,计数:numberOfBytesRead)
totalReadCount+=numberOfBytesRead
}
返回totalReadCount
}
}
扩展输出流{
@可丢弃结果
func write(数据:数据)->Int{
如果streamStatus!=打开{
开()
}
让计数=data.count
让结果=data.withUnsafeBytes{
写入($0.bindMemory(to:UInt8.self).baseAddress!,maxLength:count)
}
关闭()
返回结果
}
}
如果有人可以查看我的代码并帮助我解决问题,那将非常有帮助。
我有一种感觉,问题在于stream open()和close(),最初,除了在编写过程中添加open和close函数外,什么都不起作用。也许我需要一个更好的方法来解决这个问题。
PS:我在CocoaAsyncSocket上也遇到了同样的问题,我不打算使用它或任何其他第三方解决方案。在有限的代码中,唯一跳出来的是
close()
在write
之后。这在处理流(任何语言)时都是不正常的。特别是在swift中,流一旦关闭,就无法重新打开。
。谢谢,我不带它试试。有一件事我也意识到我正在一次写入所有数据。我将尝试使用输出缓冲区。我写的代码在我共享的输出流扩展中。这是我发现的,在你第一次写的时候,你只需要按bear最小值(我不知道为什么OutputStreams有一个hasSpaceAvailable
,但没有告诉你多少。无论如何,你应该(1)向缓冲区添加数据(2)尝试写缓冲区(3)查看写入了多少(4)从缓冲区中删除那么多(5)此时流委托将接管。使用有限的代码跳出的唯一内容是write
之后的close()
。这在处理流时是不正常的(在任何语言中)。特别是在swift中,流一旦关闭,就无法重新打开。
。谢谢,我将尝试不使用它。有一件事我还意识到我正在一次写入所有数据。我将尝试使用输出缓冲区。我的写入代码在我共享的输出流扩展中。这是我发现的,在第一次写入时,您只需按b键ear最小值(我不知道为什么OutputStreams有一个可用的hasspace
,但不告诉您有多少可用。无论如何,您应该(1)向缓冲区添加数据(2)尝试写入缓冲区(3)查看写入了多少(4)从缓冲区中删除多少(5)此时\u流委托将接管。