在 Objective C 中编写网络服务器——上传较大文件时获取 SIGPIPE 调用

发布于 2024-11-03 06:11:32 字数 1183 浏览 0 评论 0原文

我正在为音乐共享应用程序编写一个网络服务器...当我有一个大文件(即 mp3)时,这不起作用。它因 SIGPIPE 错误代码而崩溃。我发送的标头有“连接:关闭”——但我认为这会等到下载完成后关闭连接。我知道这可能应该分叉到一个线程中,但为了测试我想让它同步工作。

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.
}

I am writing a webserver for a music sharing app ... when I have a large file (i.e an mp3) this does not work. It crashes on SIGPIPE error code. The header I am sending has "Connection: close" -- but I assumed this would wait until after the download finishes to close the connection. I know this should probably be forked into a thread but for testing i want to get it working synchronously.

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.
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

染墨丶若流云 2024-11-10 06:11:32

Web 服务器必须应对客户端提前关闭连接的情况——也许它已经足够了,或者页面加载或下载被取消。即使服务器写入正确,也可能发生这种情况。您看过对话的数据包捕获吗?

A web server has to cope with the case where the client closes the connection early -- perhaps it has enough, or the page load or download was canceled. This can happen even when the server is written correctly. Have you looked at a packet capture of the conversation?

朕就是辣么酷 2024-11-10 06:11:32

您应该查看 如何防止 SIGPIPE(或处理它们)正确)

这有点重复,但基本上在您的应用首次启动时使用 signal(SIGPIPE, SIG_IGN); 。这将防止发出 SIGPIPE 信号(即您的应用程序不会崩溃)。当您想在本地处理问题时,通常会这样做。您可以通过执行以下操作在本地进行检查:

if ([fileHandle writeData:(NSData *)headerData] > 0 &&
    [fileHandle writeData:fileData] > 0)
{
   // writes succeeded, ...
}
else
{
   // write failed for some reason
}

您还可以使用 NSStreamstreamErrorstreamStatus 属性。

You should check out How to prevent SIGPIPEs (or handle them properly).

This is a bit of a rehash, but basically use signal(SIGPIPE, SIG_IGN); when your app first launches. This will prevent the SIGPIPE from being signaled (i.e. your app won't crash). You usually do this when you want to handle the problem locally. You can check locally by doing something like:

if ([fileHandle writeData:(NSData *)headerData] > 0 &&
    [fileHandle writeData:fileData] > 0)
{
   // writes succeeded, ...
}
else
{
   // write failed for some reason
}

You can additionally check for errors using NSStream's streamError or streamStatus properties.

戏剧牡丹亭 2024-11-10 06:11:32

虽然你确实应该处理 SIGPIPE。但我猜你为什么得到它是因为你在发送数据之前没有检查请求方法。
下载器很可能会先发送 HEAD 请求来获取内容长度和其他信息。

当收到 HEAD 请求时,不应调用 [fileHandle writeData:fileData]。
我猜您正在使用 此处的 HTTPServer 代码< /a>.如果是这样,您可以这样做:

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

除此之外,您可能还需要处理范围请求以避免 SIGPIPE。也许还有其他东西。编写一个 HTTP 服务器来为现实世界的请求者提供服务并不容易。

Though you really should deal with SIGPIPE. But I guess why you get it is because you didn't check request method before sending data.
It is very possible that a downloader will send a HEAD request first to get the content length and other information.

When you get a HEAD request, you should not call [fileHandle writeData:fileData].
I guess you are using the HTTPServer code from here. If so, you can just do this:

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

Other than that, you may also need to cope with range request to avoid SIGPIPE. And maybe other stuff. It is not easy to write a HTTP server to serve real world requester.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文