我在尝试使用AsyncSocket时遇到了一个奇怪的问题。在我的应用程序中,我实际上需要同步套接字,因为我自己在后台处理所有不同级别的通信。因此,我尝试围绕AsyncSocket类SyncSocket编写包装器。这是代码:
// SyncSocket.h
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
@interface SyncSocket : NSObject <AsyncSocketDelegate> {
AsyncSocket* _asyncSocket;
NSTimeInterval _connectTimeout;
NSTimeInterval _readTimeout;
NSTimeInterval _writeTimeout;
BOOL _waiting;
BOOL _nsLog;
}
@property (nonatomic, assign) BOOL waiting;
@property (nonatomic, assign) BOOL nsLog;
- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout;
- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port;
@end
// SyncSocket.m
#import "SyncSocket.h"
@implementation SyncSocket
@synthesize waiting = _waiting;
@synthesize nsLog = _nsLog;
//
// Constructor/destructor
//
- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout {
[super init];
if (self == nil)
return self;
_connectTimeout = connectTimeout;
_readTimeout = readTimeout;
_writeTimeout = writeTimeout;
_waiting = NO;
_asyncSocket = [[AsyncSocket alloc] initWithDelegate: self];
return self;
}
- (void) dealloc {
[_asyncSocket release];
[super dealloc];
}
- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port {
if (self.nsLog)
NSLog (@"connectToHost: %@ onPort: %d", host, port);
_waiting = YES;
NSError* err = nil;
if (![_asyncSocket connectToHost: host
onPort: port
withTimeout: _connectTimeout
error: &err])
return NO;
while (self.waiting && [_asyncSocket isConnected] == NO) {
[NSThread sleepForTimeInterval: 0.01];
}
return [_asyncSocket isConnected];
}
- (void) writeData: (NSData*) data {
_waiting = YES;
[_asyncSocket writeData: data withTimeout: _writeTimeout tag: 0];
while (self.waiting) {
[NSThread sleepForTimeInterval: 0.01];
}
}
//
// AsyncSocket delegates
//
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock {
if (self.nsLog)
NSLog (@"onSocketWillConnect:");
return YES;
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
if (self.nsLog)
NSLog (@"didWriteDataWithTag: %d", tag);
_waiting = NO;
}
- (void) onSocket: (AsyncSocket*) sock willDisconnectWithError: (NSError*) err {
if (self.nsLog)
NSLog (@"willDisconnectWithError: %d", [err code]);
_waiting = NO;
}
- (void) onSocket: (AsyncSocket*) sock didConnectToHost: (NSString*) host port: (UInt16) port {
if (self.nsLog)
NSLog (@"didConnectToHost: %@ port: %d", host, port);
_waiting = NO;
}
@end
问题是:AsyncSocket可以很好地连接到主机,但是永远不会调用我的委托didConnetToHost。而且,如果我调试AsyncSocket代码,即使设置了
respondsToSelector
,我也可以看到失败。看起来好像有一些奇怪的内存冲突之类的东西,但是我不知道我在哪里犯了错误。有任何想法吗?关于如何将AsyncSocket封装为同步套接字,有一个很好的例子吗?
PS:只需清楚一点:XCode 3.2.5,iPhone Simulator 4.2。
更新:之所以尝试用SyncSocket包装它,是因为我想从应用程序的业务逻辑中隐藏所有套接字委托的内容。我需要在许多不同的地方使用套接字连接,并且我不想在许多不同的地方实现底层的套接字功能(例如检测套接字的状态,接收消息的标头,然后是正文等)。我想要一个简单的界面,在其中我可以打开/发送/接收并且不必担心底层实现。我确实知道网络连接应该在单独的线程中运行,这很好-在主线程中委派一名后台工作人员不是问题。
因此,我以AsyncSocket存储库中的InterfaceTest示例为起点。从那里删除了DNS相关的内容。工作良好。 didConnect被调用,一切都闪闪发亮。
然后,我将SyncSocket实现添加到项目中,以查看问题所在。可以在这里下载项目:http://dl.dropbox.com/u/6402890/NetworkTest.zip-可能有人可以告诉我我做错了什么-我感到我在SyncSocket中没有正确使用线程。
如果我在等待循环中同时使用
asyncSocket is Connected
和内部的self.waiting
-它会退出该循环并调用didConnect
(但在循环结束后)。如果我尝试仅使用在didConnect中设置的self.waiting
-永不调用didConnect
且应用程序挂起。谁能告诉我怎么了?
最佳答案
发现问题。看起来我不得不从更改使用的等待循环:
[[NSThread sleepForTimeInterval: 0.01]
要使用RunLoop:
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];