- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在我的 iOS 应用程序中遇到了 EPIPE 问题,并且它没有被 @try/@catch/@finally block 捕获。我怎样才能捕捉到这个信号(SIGPIPE,可能)......
我已经在我的应用程序中构建了一个“网络代理”来处理某些类型的 URL - 在这种错误情况下,似乎远程端(也在我的应用程序中,但隐藏在 iOS 库中)关闭了它的套接字端.我没有收到通知(我应该吗?有什么我应该在 NSFileHandle 注册的东西可能对这里有帮助吗?)。
我将此代理基于 Matt Gallagher 放在一起的 HTTPServer(可用 here ),问题出在 HTTPRequestHandler
的子类中他整理的课。下面是代码(此代码相当于基类中的 startResponse
方法):
-(void)proxyTS:(SSProxyTSResource *)proxyTS didReceiveResource:(NSData *)resource
{
NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
CFHTTPMessageRef response =
CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)@"Content-Type",
(__bridge CFStringRef)s_MIMEtype);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)@"Connection",
(CFStringRef)@"close");
CFHTTPMessageSetBody(response,
(__bridge CFDataRef)resource);
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
@try
{
NSLog(@" -> writing %u bytes to filehandle...",[((__bridge NSData *)headerData) length]);
[self.fileHandle writeData:(__bridge NSData *)headerData];
}
@catch (NSException *exception)
{
// Ignore the exception, it normally just means the client
// closed the connection from the other end.
}
@finally
{
NSLog(@" *ding*");
CFRelease(headerData);
CFRelease(response);
[self.server closeHandler:self];
}
}
Jan 15 14:55:10 AWT-NoTouch-iPhone-1 Streamer[1788] <Warning>: [SSProxyTSResponseHandler proxyTS:didReceiveResource:]
Jan 15 14:55:10 iPhone-1 Streamer[1788] <Warning>: -> writing 261760 bytes to filehandle...
Jan 15 14:55:11 iPhone-1 com.apple.launchd[1] (UIKitApplication:com.XXX.Streamer[0xf58][1788]) <Warning>: (UIKitApplication:com.XXX.Streamer[0xf58]) Exited abnormally: Broken pipe: 13
write()
失败了,所以如果有人能指出我如何发现它已经关闭而不尝试向它写入数据,或者任何使它不会崩溃我的程序的方法,那将非常有帮助。
最佳答案
SIGPIPE 崩溃的直接问题得到了解决。我对这个解决方案并不完全傻笑,但至少应用程序不会崩溃。目前尚不清楚它是否 100% 正确工作,但它的表现似乎要好一些。
我通过进一步检查正在发生的事情解决了这个问题。在做一些研究时,我发现也许我应该使用 NSFileHandle 的 writeabilityHandler
属性来安装一个 block 来做写作。我并没有完全接受这种方法(这让我感到很困惑),但它可能会有所帮助。
可写处理程序解决方案:
在 writeabilityHandler
上进行一些网络搜索时,我偶然发现了Bert Leung's blog entry关于他在类似领域遇到的一些问题。我把他的代码修改如下,替换了@try/@catch/@finally
上面的代码块:
self.pendingData = [NSMutableData dataWithData:(__bridge NSData *)(headerData)];
CFRelease(headerData);
CFRelease(response);
self.fileHandle.writeabilityHandler = ^(NSFileHandle* thisFileHandle)
{
int amountSent = send([thisFileHandle fileDescriptor],
[self.pendingData bytes],
[self.pendingData length],
MSG_DONTWAIT);
if (amountSent < 0) {
// errno is provided by system
NSLog(@"[%@ %@] Error while sending response: %d", NSStringFromClass([self class]), NSStringFromSelector(_cmd), errno);
// Setting the length to 0 will cause this handler to complete processing.
self.pendingData.length = 0;
} else {
[self.pendingData replaceBytesInRange:NSMakeRange(0, amountSent)
withBytes:NULL
length:0];
}
if ([self.pendingData length] == 0) {
thisFileHandle.writeabilityHandler = nil;
// Hack to avoid ARC cycle with self. I don't like this, but...
[[NSNotificationCenter defaultCenter] postNotification:self.myNotification];
}
};
writeData:
的作用几乎相同。做了但使用
send()
反而。关键区别在于使用
send()
允许
errno
要设置。实际上,这很有帮助 - 我收到了几个错误代码(在 errno 中),例如 54(对等连接重置)和 32(断管)。 54 的很好,但 32 的结果是 SIGPIPE/EPIPE。然后我恍然大悟——也许我应该忽略 SIGPIPE。
UIApplicationDelegate
中添加了几个钩子(Hook)。在
application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[self installSignalHandlers];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
...
applicationWillTerminate:
:
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self removeSignalHandlers];
[self saveContext];
}
-(void)installSignalHandlers
{
signal(SIGPIPE,SIG_IGN);
}
-(void)removeSignalHandlers
{
signal(SIGPIPE, SIG_DFL);
}
@try/@catch/@finally
结构,因为它更直接。此外,在忽略 SIGPIPE 后,
@catch
block 确实被触发。现在,我正在记录异常,但只有这样我才能看到它正在工作。在发布的代码中,该日志将被禁用。
关于ios - 如何在我的 NSFIleHandle 处理中捕获 EPIPE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14347276/
我是一名优秀的程序员,十分优秀!