【发布时间】:2017-12-08 20:48:38
【问题描述】:
我知道,这个主题的标题很笼统,我认为这个问题很容易解决(我在 Android 上很容易做到)。但是在 iOS 上……嗯,这个问题是存在的……
我有一个设备,我想在它上面传输数据(准确地说是音频数据)。我必须使用的协议是 HTTP。实际上,我必须构建并发送一个在其正文中包含一些数据的 HTTP 请求,然后,当我的“生产者”(这里是重新采样/编码音频数据的过程)提供要传输的新数据时,通过它发送它请求正文。对于 HTTP 来说这听起来很奇怪,但它就像是没有边界的 HTTP 多部分(数据只是一个接一个地发送)。
例如,在 Java 中,我使用 URL 和标头初始化 HttpUrlConnection,我使用 /*my connection*/.setFixedLengthStreamingMode(9999999); 将 Content-Length 标头精确到“9999999”(如目标设备文档中所写)。我不打电话给connect()method,但我得到了输出流(getOutputStream()),当我的生产者提供新数据时,我只打电话给/*my output stream*/.write(/*my data*/);然后/*my output stream*/.flush();
所以,我尝试使用 NSURLSession 和低级 API NSInputStream 和 NSOutputStream。但在每种情况下,我都无法做到:
使用
NSURLSession,我调用了uploadTaskWithStreamedRequest:,但回调needNewBodyStream:只调用一次(或者在新身份验证的情况下调用两次)。所以我只在输入流中发送一个数据包。使用
NSInputStream和NSOutputStream连接已被目标设备正确关闭,然后我可以发送任何以输入流结尾的标准 TCP 数据(HTTP 标头除外)。
我认为这是很多人都做过的事情,而且他们是我没有看到的一种方式,不是吗?请通过给我示例(这将是完美的)或建议我必须选择什么 API 或应用特定参数来帮助我?
谢谢!
编辑
我的问题类似于 this,但这是另一种(更短的)解释方式。
编辑 2
这是我使用 NSURLSession 时的代码(如果可能,我更喜欢继续使用它):
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];
确切地说,我没有在 URL 中输入身份验证信息。代表的方法按以下顺序调用:didSendBodyData -> didReceiveChallenge(这是我执行身份验证的地方,它有效,因为我在 401 之前收到,之后什么都没有) -> needNewBodyStream(这是我放置数据的地方在完成处理程序的输入流中)-> didSendBodyData -> didFinishCollectingMetrics -> didCompleteWithError(代码为 -1005:kCFErrorDomainCFNetwork)。奇怪的是数据传输良好(第一个数据包),因为我可以在目标设备中听到一些瞬间的声音。
再次准确地说,这是连接期间的网络流量:
- 发送 TCP SYN、ECN、CWR
- Rcv TCP SYN、ACK、ECN
- 发送 TCP ACK
- 发送重组 PDU 的 TCP 段(我的 HTTP 请求和数据没有身份验证)(x7,每个后跟一个 ACK 响应)
- Rcv HTTP 401(因为需要摘要)
- ... TCP ACK、FIN/ACK、SYN/ECN/CWR 的连续...
- 发送重组 PDU 的 TCP 段(我的 HTTP 请求和数据 with 身份验证)(x7,每个后跟一个 ACK 响应)
然后(我不知道为什么):
- Rcv TCP END, ACK
- 发送 TCP ACK
- 发送 TCP END、ACK
- Rcv TCP ACK
【问题讨论】:
-
您是使用共享的 URLSession 还是创建了新的默认会话或后台会话?在第二种情况下尝试设置
sessionConfig.isDiscretionary = false和sessionConfig.networkServiceType属性 -
@Roran 感谢您的评论,我用一些代码编辑了我的问题,显示了我的 NSURLSession 用法。我试过你说的,但行为没有区别。
-
你可以试试看这个:link
-
@Roran 谢谢,我读过了,但它是用于“一次性”数据上传,我的问题是连续上传数据。