Problem with TCP-IP client connection

Discussion in 'iOS Programming' started by igorland, Jul 29, 2014.

  1. igorland macrumors newbie

    Joined:
    Mar 4, 2014
    #1
    Hello. I have an application with different tabs. Tab Setting has a textfield where a TCP-IP address of the server can be inserted. It also has a switch turning on and off TCP-IP connection. The code is:
    Code:
    - (IBAction)connectToNetwork:(UISwitch *)sender {
        
        if(self.switchNetworkConnection.on) {
            
            // Connection with the server
            [self initNetworkCommunication];
            
            appDelegate.isConnectionAvailableDelegate = YES;
        }
        
        else {
            // Disconnect from server
            [self closeNetworkCommunication];
            
            appDelegate.isConnectionAvailableDelegate = NO;
        }
        
    }
    
    
    // Initiate network communication.
    
    - (void)initNetworkCommunication {
    
        // IP Address and port
        NSString *ipAddressString = appDelegate.ipAddressDelegate;
        // Transfer NSString to CFStringRef
        CFStringRef ipAddress = (__bridge CFStringRef)ipAddressString;
        
        UInt32 ipPortInt = [appDelegate.ipPortDelegate intValue];
        
    	CFReadStreamRef readStream;
    	CFWriteStreamRef writeStream;
    	CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ipAddress, ipPortInt, &readStream, &writeStream);
    	
        inputStream = objc_unretainedObject(readStream);
    	outputStream = objc_unretainedObject(writeStream);
    	[inputStream setDelegate:self];
    	[outputStream setDelegate:self];
    	[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    	[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    	[inputStream open];
    	[outputStream open];
        
        NSLog(@"ACARS communication initiated");
    }
    
    // Close network communication.
    - (void)closeNetworkCommunication {
        
        [inputStream close];
        [outputStream close];
        [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                               forMode:NSDefaultRunLoopMode];
        [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                                forMode:NSDefaultRunLoopMode];
        [inputStream setDelegate:nil];
        [outputStream setDelegate:nil];
        inputStream = nil;
        outputStream = nil;
        
        NSLog(@"ACARS communication closed");
    }
    
    // Stream
    
    - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
        
        NSLog(@"stream event %i", streamEvent);
    	
    	switch (streamEvent)
        {
            case NSStreamEventNone:
            {
                NSLog(@"NSStreamEventNone");
            }
                break;
    			
    		case NSStreamEventOpenCompleted:
            {
    			NSLog(@"NSStreamEventOpenCompleted");
            }
                break;
                
            case NSStreamEventHasBytesAvailable:
            {
                NSLog(@"NSStreamEventHasBytesAvailable");
                
    			if (theStream == inputStream)
                {
    				uint8_t buffer[1024];
    				int len;
    				
    				while ([inputStream hasBytesAvailable])
                    {
    					len = [inputStream read:buffer maxLength:sizeof(buffer)];
    					if (len > 0)
                        {
                            NSMutableString *output = [[NSMutableString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
    						
                            // Implement a method that reads the message sent from the server
                            [self messageReceived:output];
                        }
    				}
                }
                
                appDelegate.isConnectionAvailableDelegate = YES;
                
            }
                break;
                
    		case NSStreamEventErrorOccurred:
            {
                NSLog(@"NSStreamEventErrorOccurred");
                //Connection switch back to off
                [self.switchNetworkConnection setOn:NO animated:YES];
                
                // Disconnect from server
                [self closeNetworkCommunication];
                
                // Stop activity indicator
                //[self.activityIndicator stopAnimating];
                
                // Pop-up message that the address is not valid
                UIAlertView* disconnectMsg;
                disconnectMsg = [[UIAlertView alloc] initWithTitle:@"No Connection with Server"
                                                           message:@"No connection."
                                                          delegate:self
                                                 cancelButtonTitle:@"OK"
                                                 otherButtonTitles:nil, nil];
                [disconnectMsg show];
                
                appDelegate.isConnectionAvailableDelegate = NO;
            }
                break;
    			
    		case NSStreamEventEndEncountered:
            {
                NSLog(@"NSStreamEventEndEncountered");
                
                [theStream close];
                [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                theStream = nil;
                appDelegate.isConnectionAvailableDelegate = NO;
            }
                break;
                
            default:
            {
    			NSLog(@"Unknown event");
            }
                break;
    	}
        
    }
    
    
    // Messages that are received from the server.
    
    - (void) messageReceived:(NSString *)message {
        
        NSLog(@"MAP MESSAGE RECEIVED: %@",message);
    }
    
    // Messages that contain the code sent to the server. As a result the server will reply with data
    
    - (void)sendMapMessageToServer {
        NSString *response  = [NSString stringWithFormat:@"MESSAGE_TO_SERVER:"];
    	NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
    	[outputStream write:[data bytes] maxLength:[data length]];
        
        NSLog(@"MAPPING SECOND MESSAGE SENT");
        
    }
    
    
    In the second ViewPanel, I have another switch that turns on a timer to call the sendMapMessageToServer every 5 seconds:

    Code:
    - (IBAction)connectToServer:(UISwitch *)sender {
        
        if(self.switchConnection.on) {
            
            // Setting timer at 5 sec by default
            connectionTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0
                                                               target: self
                                                             selector: @selector(loadDataToServer)
                                                             userInfo: nil
                                                              repeats: YES];
        }
        
        else {
            // Stop timer
            [connectionTimer invalidate];
            connectionTimer = nil;
        }
    }
    
    
    -(void) loadDataToServer {
        
        NSLog(@"LOADINGDATATOTHEMAP");
        
        self.settingVC = [[IGASettingsViewController alloc]init];
        
        [self.settingVC sendMapMessageToServer];
    }
    

    So, when I do it, I see the message "MAPPING SECOND MESSAGE SENT". So, the method is called, however for some reason, the message is not sent to the server. When I trigger sending the message from the same tab (class) it seems to work, so there should not be any problem with the server.

    I am stuck.

    Thank you!
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Your loadDataToServer method creates a new view controller every time before it tries to send the data. I don't think that's what you want. You want to only create a single view controller and then reuse that object.

    The sendMapMessageToServer method depends on an output stream and a response that almost certainly don't exist when you first create the view controller.
     
  3. igorland thread starter macrumors newbie

    Joined:
    Mar 4, 2014
    #3
    Thanks, PhoneyDeveloper. But I do not understand why. I turn the connection switch on, so [self initNetworkCommunication] method should be called in the Setting UIViewController, i.e. input and output streams should be open and available. They do not close when I go to another UIViewController, do they?

    Thanks!
     
  4. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #4
    These lines create a new view controller but don't put it into the view hierarchy. That's odd. Does the IGASettingsViewController init method call initNetworkCommunication? If not then the streams for this instance of the view controller aren't open and the sendMapMessageToServer method will fail because of that.

    Code:
      
    self.settingVC = [[IGASettingsViewController alloc]init];
        
    [self.settingVC sendMapMessageToServer];
    
    (btw, you should only use the name init in real init methods. Instead call that method something like startNetworkCommunications or setupNetworkCommunications.)
     
  5. igorland thread starter macrumors newbie

    Joined:
    Mar 4, 2014
    #5
    PhoneyDeveloper, thanks. It took me a while to try out different methods to come up with the solution. Now I have buttons in both ViewControllers that initiate communication with the server and start streaming. Once the message is sent, the stream is closed, so they do not interfere. I also changed my code for
    Code:
    - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
    The original code that I took from a tutorial has a lot of potential errors in it, as I have been explained. Anyways, the problem has been solved not as I originally intended but satisfactory. Thank you for your help!
     

Share This Page