我面临使用HTTP文件上传上传文件的问题。根据客户端 - 服务器的理解遵循的协议是,http请求标头 应首先上传txn,然后是一个流,该流应包含请求XML的数据,后跟文件缓冲区的数据。
现在,请求标头到达,服务器在读取标头后开始读取流。它也从流中获取请求XML。
此后,服务器从流中读取文件数据。文件上传完成后,我尝试下载相同的文件。在服务器中,我看到文件在那里,它也显示正确的大小。
下载文件后,我发现文件最终被裁剪(如果是jpg文件)或者某些结束文本丢失(如果是txt文件)。
根据我项目的逻辑,数据以8KB的块传输。我已经验证了最后一个小于8KB的块是导致裁剪的缺失数据 的图像。我还验证了最后一个块在fileHandler API形成的缓冲区中有有效数据。我发送了一些我用于写入逻辑的代码片段。
您能否确定最后一个块没有流式传输或某些垃圾数据流式传输代替最后一个块的特定原因?
用于创建写入流的代码段:
const UInt8 *uploadBuf;
uploadBuf = (const UInt8*)malloc(totLen);
CFReadStreamRef readStreamForBody = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, uploadBuf, (CFIndex)totLen, kCFAllocatorNull);
CFReadStreamRef readStreamForUpload = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, messageRef, readStreamForBody);
if (CFReadStreamOpen(readStreamForUpload) == TRUE)
{
CFWriteStreamRef writeStream = CFWriteStreamCreateWithBuffer(kCFAllocatorDefault, (UInt8*)uploadBuf, (CFIndex)totLen);
if (CFWriteStreamOpen(writeStream) == FALSE)
{
CFErrorRef streamError = CFWriteStreamCopyError(writeStream);
CFStringRef streamErrorString = CFErrorCopyDescription(streamError);
CFShow(streamErrorString);
CFRelease(streamError);
CFRelease(streamErrorString);
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
writeStream = NULL;
}
else
{
Boolean hasBytes = FALSE;
CFStreamStatus streamStatus = CFWriteStreamGetStatus(writeStream);
do
{
while ((hasBytes == FALSE) &&
((streamStatus != kCFStreamStatusNotOpen) &&
(streamStatus != kCFStreamStatusAtEnd) &&
(streamStatus != kCFStreamStatusClosed) &&
(streamStatus != kCFStreamStatusError)))
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false);
hasBytes = CFWriteStreamCanAcceptBytes(writeStream);
streamStatus = CFWriteStreamGetStatus(writeStream);
}
} while (hasBytes != TRUE);
用于保存写入流的代码段:
[self setWriteStreamForFile:writeStream];
[[MyHTTPLastRequestList lastRequestList] setObject:self forKey:[self sessionKey]];
用于将缓冲区写入writestream的代码片段:
- (void) write:(const void*)fileBuffer numBytes:(NSUInteger)fileBufSize
{
MyThreadSafeDictionary *lastRequestList = [MyHTTPLastRequestList lastRequestList];
NSString *sessionKey = [self sessionKey];
BOOL noResponse = YES;
while (noResponse)
noResponse = ([lastRequestList objectForKey:sessionKey] == nil);
MyHTTPMessage *httpFileUploadMsg = (MyHTTPMessage*)[lastRequestList objectForKey:sessionKey];
CFIndex totalLen = [httpFileUploadMsg totalLength];
CFIndex sentLen = [httpFileUploadMsg sentLength];
NSData *chunkData = [[[NSData dataWithBytes:fileBuffer length:fileBufSize] retain] autorelease];
sentLen += (CFIndex)fileBufSize;
CFIndex bytesRemaining = totalLen - sentLen;
CFIndex bytesWritten = 0;
CFWriteStreamRef writeStream = [httpFileUploadMsg writeStreamForFile];
if (bytesRemaining > 0)
{
CFWriteStreamRef writeStream = [httpFileUploadMsg writeStreamForFile];
bytesWritten = CFWriteStreamWrite(writeStream, (const UInt8*)[chunkData bytes], (CFIndex)fileBufSize);
[httpFileUploadMsg setSentLength:sentLen];
NSLog(@"Bytes written to stream = %d",(NSInteger)sentLen);
[httpFileUploadMsg setWriteStreamForFile:writeStream];
}
else
{
@try
{
bytesWritten = CFWriteStreamWrite(writeStream, (const UInt8*)[chunkData bytes], (CFIndex)fileBufSize);
if (bytesWritten == 0)
{
NSLog(@"ERROR :: Stream Filled to capacity");
}
else if (bytesWritten < 0)
{
NSLog(@"ERROR :: Write failed.");
CFErrorRef streamError = CFWriteStreamCopyError(writeStream);
CFStringRef streamErrorString = CFErrorCopyDescription(streamError);
CFShow(streamErrorString);
CFRelease(streamError);
CFRelease(streamErrorString);
}
else
{
NSLog(@"Write Success");
}
}
@catch (NSException* localException)
{
NSLog(@"Exception raised - %@",[localException name]);
[localException raise];
}
NSLog(@"Sending to the server");
CFReadStreamRef readStreamForUpload = [httpFileUploadMsg readStreamForHTTPResponse];
CFStreamStatus rStreamStatus = CFReadStreamGetStatus(readStreamForUpload);
Boolean parentStreamHasBytes = FALSE;
do
{
while ((parentStreamHasBytes == FALSE) &&
((rStreamStatus != kCFStreamStatusNotOpen) &&
(rStreamStatus != kCFStreamStatusAtEnd) &&
(rStreamStatus != kCFStreamStatusClosed) &&
(rStreamStatus != kCFStreamStatusError)))
{
CFRunLoopRunInMode (kCFRunLoopDefaultMode, 0, false);
parentStreamHasBytes = CFReadStreamHasBytesAvailable(readStreamForUpload);
rStreamStatus = CFReadStreamGetStatus(readStreamForUpload);
}
} while (parentStreamHasBytes != TRUE);