Написание веб-сервера в целях c- получение вызова SIGPIPE при загрузке больших файлов
Я пишу веб-сервер для приложения для обмена музыкой... когда у меня большой файл (например, mp3), это не работает. Вылетает по коду ошибки SIGPIPE. Заголовок, который я отправляю, имеет "Connection: close" - но я предполагал, что это подождет до завершения загрузки, чтобы закрыть соединение. Я знаю, что это, вероятно, должно быть разветвлено в поток, но для тестирования я хочу, чтобы он работал синхронно.
NSData *fileData =[NSData dataWithContentsOfFile:filePath];
CFHTTPMessageRef response =
CFHTTPMessageCreateResponse(
kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(
response, (CFStringRef)@"Content-Type", (CFStringRef)@"audio/mpeg");
CFHTTPMessageSetHeaderFieldValue(
response, (CFStringRef)@"Connection", (CFStringRef)@"close");
CFHTTPMessageSetHeaderFieldValue(
response,
(CFStringRef)@"Content-Length",
(CFStringRef)[NSString stringWithFormat:@"%ld", [fileData length]]);
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
@try
{
[fileHandle writeData:(NSData *)headerData];
[fileHandle writeData:fileData];
}@catch (NSException *exception)
{
// Ignore the exception, it normally just means the client
// closed the connection from the other end.
}
3 ответа
Веб-сервер должен справиться со случаем, когда клиент закрывает соединение досрочно - возможно, этого достаточно, или загрузка страницы или загрузка была отменена. Это может произойти, даже если сервер написан правильно. Вы смотрели на захват пакета разговора?
Вы должны проверить, как предотвратить SIGPIPE (или обращаться с ними правильно).
Это немного перефразировать, но в основном использовать signal(SIGPIPE, SIG_IGN);
когда ваше приложение запускается впервые. Это предотвратит сигнал SIGPIPE (т. Е. Ваше приложение не будет аварийно завершено). Обычно вы делаете это, когда хотите решить проблему локально. Вы можете проверить локально, выполнив что-то вроде:
if ([fileHandle writeData:(NSData *)headerData] > 0 &&
[fileHandle writeData:fileData] > 0)
{
// writes succeeded, ...
}
else
{
// write failed for some reason
}
Вы можете дополнительно проверить на наличие ошибок, используя NSStream
"s streamError
или же streamStatus
свойства.
Хотя вы действительно должны иметь дело с SIGPIPE. Но я думаю, почему вы получаете его, потому что вы не проверяли метод запроса перед отправкой данных.
Вполне возможно, что загрузчик сначала отправит запрос HEAD для получения длины контента и другой информации.
Когда вы получаете запрос HEAD, вы не должны вызывать [fileHandle writeData:fileData]. Я предполагаю, что вы используете код HTTPServer отсюда. Если это так, вы можете просто сделать это:
if (![requestMethod isEqualToString:@"HEAD"] && fileData)
{
[fileHandle writeData:fileData];
}
Помимо этого, вам также может потребоваться справиться с запросом диапазона, чтобы избежать SIGPIPE. И, возможно, другие вещи. Нелегко написать HTTP-сервер для обслуживания реального пользователя.