2011-11-22 134 views
1

我的應用程序在嘗試連接到主機時超時。超時時間設置爲無限制,所以我認爲客戶端根本無法連接。asyncsocket ipad未連接到服務器

我有一個運行asyncsockets的iPad應用程序,我試圖讓它連接到我的桌面上也使用asyncsockets的服務器。 iPad特別是iOS 5,並使用GCD asyncockets。

服務器正在通過NSRunLoop調用。它從客戶端沒有收到任何形式的連接(沒有捕獲像telnet連接那樣的斷點)。

我可以從其他機器telnet到服務器就好了。我也可以將iPad客戶端連接到host:google.com on port:80就好了。

我試過將iPad連接到端口8080,4500和50000上的服務器都沒有成功(它們都適用於telnet)。

我相信在服務器代碼中有東西引起這種情況,但我不確定。

我的服務器代碼是從這裏發現了一個樣本:http://mysterycoconut.com/blog/2010/07/tweak-away/

我的客戶端代碼是從由asyncsockets庫提供的樣品GCD代碼修改HTTP客戶端代碼:https://github.com/robbiehanson/CocoaAsyncSocket/blob/master/Examples/GCD/SimpleHTTPClient/Mobile/SimpleHTTPClient/SimpleHTTPClientAppDelegate.m

這裏是我的服務器代碼:

- (id) init; 
{ 
    self = [super init]; 
    if (self != nil) 
    { 
     debugServer = [[AsyncSocket alloc] initWithDelegate:self]; 
     connectedClients = [[NSMutableArray alloc] initWithCapacity:1]; 
     running = false; 
    } 
    return self; 
} 

- (void) dealloc; 
{ 
    [self stop]; 
    [connectedClients release]; 
    [debugServer release]; 
    [super dealloc]; 
} 

- (void) startOnPort 
{ 
    if (running) return; 

    if (_port < 0 || _port > 65535) 
     _port = 0; 

    NSError *error = nil; 
    if (![debugServer acceptOnPort:_port error:&error]) 
     return; 

    NSLog(@"My Awesome Debug Server has started on port %hu", [debugServer localPort]); 

    running = true; 
} 


- (void) stop; 
{ 
    if (!running) return; 

    [debugServer disconnect]; 
    for (AsyncSocket* socket in connectedClients) 
     [socket disconnect]; 

    running = false; 
} 


- (void) setPort:(int)in_port{ 
    _port = in_port; 
} 

- (void)onSocket:(AsyncSocket *)socket didAcceptNewSocket:(AsyncSocket *)newSocket; 
{ 
    [connectedClients addObject:newSocket]; 
} 


- (void)onSocketDidDisconnect:(AsyncSocket *)socket; 
{ 
    [connectedClients removeObject:socket]; 
} 

- (void)onSocket:(AsyncSocket *)socket didConnectToHost:(NSString *)host port:(UInt16)port; 
{ 
    NSLog(@"Accepted client %@:%hu", host, port); 

    NSData *welcomeData = [@"Welcome to my Awesome Debug Server\r\n\r\n" 
          dataUsingEncoding:NSUTF8StringEncoding]; 
    [socket writeData:welcomeData withTimeout:-1 tag:WelcomeMsgTag]; 

    [socket readDataWithTimeout:-1 tag:GenericMsgTag]; 
} 


- (void)onSocket:(AsyncSocket *)socket didReadData:(NSData *)data withTag:(long)tag; 
{ 
    NSString *tmp = [NSString stringWithUTF8String:[data bytes]]; 
    NSString *input = [tmp stringByTrimmingCharactersInSet: 
         [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 

    NSLog(@"%@",input); 

    if ([input isEqualToString:@"exit"]) 
    { 
     NSData *byeData = [@"Bye!\r\n" dataUsingEncoding:NSUTF8StringEncoding]; 
     [socket writeData:byeData withTimeout:-1 tag:GenericMsgTag]; 
     [socket disconnectAfterWriting]; 
     return; 
    } 

    [socket readDataWithTimeout:-1 tag:GenericMsgTag]; 
} 

@end 

...這是我的客戶端代碼:

- (id) init 
{ 
    if (self = [super init]) { 
    // AsyncSocket optionally uses the Lumberjack logging framework. 
    // 
    // Lumberjack is a professional logging framework. It's extremely fast and flexible. 
    // It also uses GCD, making it a great fit for GCDAsyncSocket. 
    // 
    // As mentioned earlier, enabling logging in GCDAsyncSocket is entirely optional. 
    // Doing so simply helps give you a deeper understanding of the inner workings of the library (if you care). 
    // You can do so at the top of GCDAsyncSocket.m, 
    // where you can also control things such as the log level, 
    // and whether or not logging should be asynchronous (helps to improve speed, and 
    // perfect for reducing interference with those pesky timing bugs in your code). 
    // 
    // There is a massive amount of documentation on the Lumberjack project page: 
    // https://github.com/CocoaLumberjack/CocoaLumberjack 
    // 
    // But this one line is all you need to instruct Lumberjack to spit out log statements to the Xcode console. 

    [DDLog addLogger:[DDTTYLogger sharedInstance]]; 

    // Create our GCDAsyncSocket instance. 
    // 
    // Notice that we give it the normal delegate AND a delegate queue. 
    // The socket will do all of its operations in a background queue, 
    // and you can tell it which thread/queue to invoke your delegate on. 
    // In this case, we're just saying invoke us on the main thread. 
    // But you can see how trivial it would be to create your own queue, 
    // and parallelize your networking processing code by having your 
    // delegate methods invoked and run on background queues. 

    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; 

    // Now we tell the ASYNCHRONOUS socket to connect. 
    // 
    // Recall that GCDAsyncSocket is ... asynchronous. 
    // This means when you tell the socket to connect, it will do so ... asynchronously. 
    // After all, do you want your main thread to block on a slow network connection? 
    // 
    // So what's with the BOOL return value, and error pointer? 
    // These are for early detection of obvious problems, such as: 
    // 
    // - The socket is already connected. 
    // - You passed in an invalid parameter. 
    // - The socket isn't configured properly. 
    // 
    // The error message might be something like "Attempting to connect without a delegate. Set a delegate first." 
    // 
    // When the asynchronous sockets connects, it will invoke the socket:didConnectToHost:port: delegate method. 

    NSError *error = nil; 

#if USE_SECURE_CONNECTION 
    uint16_t port = 443; // HTTPS 
#else 
    uint16_t port = 8080; // HTTP 
#endif 

    DDLogVerbose(@"port: %d\t host: %@",port,@"130.85.92.12"); 

    if (![asyncSocket connectToHost:@"130.85.92.12" onPort:port error:&error]) 
    { 
     DDLogError(@"Unable to connect to due to invalid configuration: %@", error); 
    } 
    else 
    { 
     DDLogVerbose(@"Connecting..."); 
    } 

#if USE_SECURE_CONNECTION 

    // The connect method above is asynchronous. 
    // At this point, the connection has been initiated, but hasn't completed. 
    // When the connection is establish, our socket:didConnectToHost:port: delegate method will be invoked. 
    // 
    // Now, for a secure connection we have to connect to the HTTPS server running on port 443. 
    // The SSL/TLS protocol runs atop TCP, so after the connection is established we want to start the TLS handshake. 
    // 
    // We already know this is what we want to do. 
    // Wouldn't it be convenient if we could tell the socket to queue the security upgrade now instead of waiting? 
    // Well in fact you can! This is part of the queued architecture of AsyncSocket. 
    // 
    // After the connection has been established, AsyncSocket will look in it's queue for the next task. 
    // There it will find, dequeue and execute our request to start the TLS security protocol. 
    // 
    // The options passed to the startTLS method are fully documented in the GCDAsyncSocket header file. 
    // The deusty server only has a development (self-signed) X.509 certificate. 
    // So we tell it not to attempt to validate the cert (cause if it did it would fail). 

    NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] 
                 forKey:(NSString *)kCFStreamSSLValidatesCertificateChain]; 

    [asyncSocket startTLS:options]; 

#endif 
    } 

    return self; 
} 

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port 
{ 
    DDLogVerbose(@"socket:didConnectToHost:%@ port:%hu", host, port); 

    // HTTP is a really simple protocol. 
    // 
    // If you don't already know all about it, this is one of the best resources I know (short and sweet): 
    // http://www.jmarshall.com/easy/http/ 
    // 
    // We're just going to tell the server to send us the metadata (essentially) about a particular resource. 
    // The server will send an http response, and then immediately close the connection. 

    NSString *msg = @"iOS client connected\r\n\r\n"; 
    NSData *msgdata = [msg dataUsingEncoding:NSUTF8StringEncoding]; 

    [asyncSocket writeData:msgdata withTimeout:-1.0 tag:0]; 

    // Side Note: 
    // 
    // The AsyncSocket family supports queued reads and writes. 
    // 
    // This means that you don't have to wait for the socket to connect before issuing your read or write commands. 
    // If you do so before the socket is connected, it will simply queue the requests, 
    // and process them after the socket is connected. 
    // Also, you can issue multiple write commands (or read commands) at a time. 
    // You don't have to wait for one write operation to complete before sending another write command. 
    // 
    // The whole point is to make YOUR code easier to write, easier to read, and easier to maintain. 
    // Do networking stuff when it is easiest for you, or when it makes the most sense for you. 
    // AsyncSocket adapts to your schedule, not the other way around. 

#if READ_HEADER_LINE_BY_LINE 

    // Now we tell the socket to read the first line of the http response header. 
    // As per the http protocol, we know each header line is terminated with a CRLF (carriage return, line feed). 

    [asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1.0 tag:0]; 
#else 

    // Now we tell the socket to read the full header for the http response. 
    // As per the http protocol, we know the header is terminated with two CRLF's (carriage return, line feed). 

    [asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1.0 tag:0]; 

#endif 
} 

- (void)socketDidSecure:(GCDAsyncSocket *)sock 
{ 
    // This method will be called if USE_SECURE_CONNECTION is set 

    DDLogVerbose(@"socketDidSecure:"); 
} 

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag 
{ 
    DDLogVerbose(@"socket:didWriteDataWithTag:"); 
} 

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 
{ 
    DDLogVerbose(@"socket:didReadData:withTag:"); 

    NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 

    NSLog(@"%@",httpResponse); 

#if READ_HEADER_LINE_BY_LINE 

    DDLogInfo(@"Line httpResponse: %@", httpResponse); 

    // As per the http protocol, we know the header is terminated with two CRLF's. 
    // In other words, an empty line. 

    if ([data length] == 2) // 2 bytes = CRLF 
    { 
     DDLogInfo(@"<done>"); 
    } 
    else 
    { 
     // Read the next line of the header 
     [asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1.0 tag:0]; 
    } 

#else 

    DDLogInfo(@"Full httpResponse: %@", httpResponse); 

#endif 

    [httpResponse release]; 
} 

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err 
{ 
    // Since we requested HTTP/1.0, we expect the server to close the connection as soon as it has sent the response. 

    DDLogVerbose(@"socketDidDisconnect:withError: \"%@\"", err); 
} 

我環顧四周尋找答案,但沒有成功。我認爲最好的行動方式是問問你們所有人,而不是讓自己的大腦試圖自己解決。

回答

1

解決方案是以不同方式連接到本地網絡。我使用的網絡需要登錄才能進行本地訪問,但爲廣域網訪問提供了「訪問者」連接。設備(iPad)以「訪問者」身份自動連接,我需要手動登錄。

因此,如果您無法連接到此API,請查看您的網絡連接方式!