我知道,这个主题的标题非常通用,我认为这个问题很容易解决(我很容易在Android上制作)。但是在iOS上......嗯,这个问题存在......
我有一台设备,我想在其上传输数据(音频数据准确)。我必须使用的协议是HTTP。实际上,我必须构建ans发送一个包含其身体中的一些数据的HTTP请求,然后,当我的“生产者”(这里是重新采样/编码音频数据的过程)给出要传输的新数据时,通过它发送它请求机构。这对于HTTP来说听起来很奇怪,但它就像没有边界的HTTP多部分(数据只是一个接一个地发送)。
例如,在Java中,我使用URL和标题初始化HttpUrlConnection
,我将Content-Length
标题精确到“9999999”(因为它是在目标设备的文档中写的){{1} }。我没有调用/*my connection*/.setFixedLengthStreamingMode(9999999);
方法,但我得到输出流(connect()
),当我的制作人提供新数据时,我只需拨打getOutputStream()
然后/*my output stream*/.write(/*my data*/);
所以,我尝试使用/*my output stream*/.flush();
和低级API NSURLSession
和NSInputStream
。但在每种情况下,我都无法做到:
使用NSOutputStream
我调用NSURLSession
但回调uploadTaskWithStreamedRequest:
仅调用一次(或者在新身份验证时调用两次)。所以我只在输入流中发送一个数据包。
在我发送任何标准TCP以输入流结尾的数据(HTTP标头除外)之前,目标设备关闭needNewBodyStream:
和NSInputStream
连接没有错误。
我认为这是许多人所做的事情,他们是我没有看到的方式,不是吗?请帮助我给我举例(这将是完美的)或关于我必须选择什么API或要应用的特定参数?
谢谢!
修改
我的问题类似于 this ,但这是解释它的另一种(更短)方式。
编辑2
这是我使用NSURLSession时的代码(如果可能,我更喜欢继续使用):
NSOutputStream
确切地说,我没有在网址中输入身份验证信息。代表的方法按此顺序调用:NSURLSessionConfiguration* defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue* operationQueue = [NSOperationQueue mainQueue];
NSURLSession* session = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:self delegateQueue:operationQueue];
NSInputStream* inputStream = [NSInputStream inputStreamWithData:/*data*/];
NSURL* url = /*init from string*/
NSMutableRequest* request : [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBodyStream = inputStream;
/*Add some headers to request*/
NSURLSessionUploadTask* uploadTask = [session uploadTaskWithStreamedRequest:request];
[uploadTask resume];
- > didSendBodyData
(这是我执行身份验证的地方,它起作用,因为我在401之前收到,之后没有收到) - > didReceiveChallenge
(这是我将数据放入完成处理程序的输入流中的位置) - > needNewBodyStream
- > didSendBodyData
- > didFinishCollectingMetrics
(代码为-1005:kCFErrorDomainCFNetwork)。奇怪的是,数据传输得很好(第一个数据包),因为我可以在某些瞬间听到目标设备中的声音。
更准确地说,这是连接期间的网络流量:
然后(我不知道为什么):
答案 0 :(得分:0)
好的,我已经得到了答案,我认为分享它是一个好主意。实际上这很容易:诀窍根本就不明确。回调needNewBodyStream:
被调用一次(或更多,请参阅doc),我们只需要将NSInputStream
对象与NSOutputStream
对象绑定。然后,当“生产者”提供新数据时,数据将在NSOutputStream
的回调中写入。以前,我的连接已关闭,因为在needNewBodyStream
通话后没有任何内容可以发送。
NSURLSessionTaskDelegate
实施的一部分:
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * bodyStream))completionHandler
{
NSInputStream* inputStream = nil;
NSOutputStream* outputStream = nil;
// Bind inputStream and outputStream
self.inputStream = inputStream;
self.outputStream = outputStream;
[self.outputStream setDelegate:/*NSStreamDelegate implementation*/];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream open];
completionHandler(self.inputStream);
}
NSStreamDelegate
实施的一部分:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventOpenCompleted:
// to handle...
break;
case NSStreamEventHasSpaceAvailable:
// Producer/Consumer's consumer here, and when data is available:
[self.outputStream write:/*data*/ maxLength:/*data length*/];
break;
case NSStreamEventErrorOccurred:
// to handle...
break;
case NSStreamEventEndEncountered:
// to handle...
break;
default:
break;
}
}
现在您可以通过HTTP流式传输“in live”,享受:)