Написание веб-сервера в целях c - получение вызова SIGPIPE при загрузке больших файлов - PullRequest
0 голосов
/ 27 апреля 2011

Я пишу веб-сервер для приложения для обмена музыкой ... когда у меня большой файл (например, 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 ]

1 голос
/ 27 апреля 2011

Веб-сервер должен справиться со случаем, когда клиент закрывает соединение раньше - возможно, этого достаточно, или загрузка страницы или загрузка была отменена.Это может произойти, даже если сервер написан правильно.Вы смотрели на захват пакета разговора?

0 голосов
/ 21 апреля 2013

Хотя вы действительно должны иметь дело с SIGPIPE. Но я думаю, почему вы получаете его, потому что вы не проверяли метод запроса перед отправкой данных.
Вполне возможно, что загрузчик сначала отправит запрос HEAD для получения длины контента и другой информации.

Когда вы получаете запрос HEAD, вы не должны вызывать [fileHandle writeData: fileData]. Я предполагаю, что вы используете код HTTPServer из здесь . Если это так, вы можете просто сделать это:

if (![requestMethod isEqualToString:@"HEAD"] && fileData)
{
  [fileHandle writeData:fileData];
}

Кроме этого, вам также может потребоваться справиться с запросом диапазона, чтобы избежать SIGPIPE. И, возможно, другие вещи. Нелегко написать HTTP-сервер для обслуживания реального пользователя.

0 голосов
/ 09 ноября 2011

Вы должны проверить Как предотвратить 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 streamError или streamStatus свойства.

...