Socket connection stream opened called two times - iphone

I have implemented socket connection in my project and it is working fine.
But my problem is that I want to send a string request on opening completion of socket.
Delegate is working fine.
- (void)initNetworkCommunication
{
lastString=#"";
isSocketAuthorized=NO;
NSLog(#"$$$$$$$$$$$$$$$$$$$$$$$$$============socket connection INITIALISED....");
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,(CFStringRef)#"XXX.XX.XXX.XX",XXXX, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventOpenCompleted:{
NSLog(#"Stream opened");
[self performSelectorInBackground:#selector(sendAuthRequest) withObject:nil];
}
break;
case NSStreamEventHasBytesAvailable:
{
if (aStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
// NSLog(#"server said: %#", output);
[self messageReceived:output];
}
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
{
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
break;
default:
NSLog(#"Unknown event");
}
}
But stream open is called twice.Why so? can anyone help me.
Thanks.

After a long time of spending my brain over the problem , I come to know that I am actually calling open stream two times.First time for Input Stream and second time for Output Stream.And at last I got the solution to fire my method once in a no of event called,I used condition for NSStream class kind.
case NSStreamEventOpenCompleted:{
if ([aStream isKindOfClass:[inputStream class]]) {
NSLog(#"Input stream opened");
}else{
NSLog(#"output stream opened");
[self performSelectorInBackground:#selector(sendAuthRequest) withObject:nil];
}
}

Related

I'm not able to send message to socket server

I have to create a chat app for iOS using socket programming .
I'm not able to receive and send data ,there are no error or crash.
My code :
-(IBAction)sendButtonAction:(id)sender
{
NSString *ipAddress = #"my server ip address";
NSString *portNo = #"my port number";
if(inputStream && outputStream)
[self close];
NSURL *website = [NSURL URLWithString:ipAddress];
if (!website)
{
NSLog(#"%# is not a valid URL", website);
}
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef) [website host], [portNo intValue], &readStream, &writeStream);
self.inputStream = (__bridge_transfer NSInputStream *)readStream;
self.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
NSLog(#"inputStream ===%#",inputStream);
NSLog(#"outputStream ===%#",outputStream);
[self open];
}
- (void)open
{
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
NSLog(#"Socket Init: %#",#"");
}
- (void)dataSending:(NSString*)data
{
NSLog(#"data ===%#",data);
if(outputStream)
{
if(![outputStream hasSpaceAvailable])
return;
NSString *response = [NSString stringWithFormat:#"%#<EOF>",data];
NSLog(#"response ===--------------->%#",response);
NSData *msgdata = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"msgdata ===--------------->%#",msgdata);
[outputStream write:[msgdata bytes] maxLength:[msgdata length]];
NSLog(#"Sent data----------------------%#",data);
}
}
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSLog(#"stream event %i", streamEvent);
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
if (theStream == inputStream)
{
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable])
{
len = [inputStream read:buffer maxLength:1024];
if (len > 0)
{
NSMutableString *output = [[NSMutableString alloc]
initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
NSLog(#"Received data--------------------%#", output);
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
event = #"NSStreamEventHasSpaceAvailable";
[self dataSending:self.messageTextFiled.text];
break;
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
[self close];
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self close];
break;
default:
event = #"Unknown";
break;
}
NSLog(#"event------%#",event);
}
I have tried a lot and googled ,but I did not find any solution.
It's killing my time so if any one have worked on it please guide me and post sample code.

Receiving broken/incomplete message using Sockets

I'm new to socket programming, I did it by referring http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server, I'm using php server, the problem I'm facing is, I'm able to send/receive messages using sockets, but my received messages are broken like My recieved msg should be "Hello abcd" but it gives me " " then after some time "llo" then after some time "abcd".
I'm using following code to receive messages:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventNone:
NSLog(#"Stream event none");
break;
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
int len=0;
uint8_t *buffer = (uint8_t *)calloc(1, (16*1024));
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
NSLog(#"byte available %d",len);
if (len > 0) {
NSMutableData* data=[[NSMutableData alloc] initWithLength:0];
//
[data appendBytes:(const void *)buffer length:len];
// NSString *s = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
// NSLog(#"rs %#",s);
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
NSLog(#"server said: %#", output);
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"event space available");
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
NSLog(#"end");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[theStream release];
theStream = nil;
break;
default:
NSLog(#"Unknown event");
}
}
I was facing same issue. What i did was instead of appending string in the delegate method i passed the string to another method, checked the inputstream for bytes and appended the string there. Here is the snippet from my app. Hope it helps.
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
NSInteger len = [inputStream read:buffer maxLength:sizeof(buffer)];
NSString *output;
if (len > 0) {
output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
[self messageReceived:output];
}
}
break;
case NSStreamEventErrorOccurred:
{
NSLog(#"Can not connect to the host!");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
UIAlertView *errorOccured = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Some error occured." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[errorOccured show];
}
break;
case NSStreamEventEndEncountered:
NSLog(#"Stream end occured");
break;
default:
NSLog(#"Unknown event");
}
}
- (void) messageReceived:(NSString *)message {
if (inputStream.hasBytesAvailable) {
[streamResponseStr appendString:message];
}else{
[streamResponseStr appendString:message];
[self parseServerResponse:streamResponseStr];
streamResponseStr = nil;
streamResponseStr = [[NSMutableString alloc] init];
}
}

NSStreamDelegate reading asynchronous data

OK. So there is an exceptional case I have to handle for NSStreamDelegate implementation.
The process is the following:
1- a COMMAND data is written to the output stream to trigger the other end
2- The other end, starts putting data for the input stream BUT asynchronously, meaning that the first part of the data is received at the beginning then a couple of seconds later, the rest of the data comes in.
3- After all the data is received, the server will NOT send any data but the connection remains open. (input stream status = Open (2))
4- After couple of minutes, the server ends the connection (input stream status = 5) and NSStreamEventEndEncountered is triggered.
SendRequest class
- (void)sendSecondRequest {
CFReadStreamRef readStream = nil;
CFWriteStreamRef writeStream = nil;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)self.SOMEServer, self.SOMEPort, &readStream, &writeStream);
self.inputStream = (__bridge NSInputStream *)readStream;
self.outputStream = (__bridge NSOutputStream *)writeStream;
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
NSData *data = [NSData dataWithData:[kSecondCall dataUsingEncoding:NSASCIIStringEncoding]];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
[self.outputStream write:[data bytes] maxLength:[data length]];
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
if (aStream == self.inputStream) {
uint8_t buffer[1024];
NSInteger len = [self.inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
[gOutput appendString:output];
}
}
break;
case NSStreamEventEndEncountered:
NSLog(#"Can not connect to the host");
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
aStream = nil;
break;
default:
break;
}
}
- (void)disconnectSocket {
[self.inputStream close];
[self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream close];
[self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream setDelegate:nil];
[self.outputStream setDelegate:nil];
self.inputStream = nil;
self.outputStream = nil;
}
The gOutput variable is a global variable that I use to read and store input stream.
The problem is that since the data's first part comes immediately and then the rest comes in asynchronously, I can not handle the moment when there is no more data available.
In other words, how can I know if the server is done sending data and I should start processing it?
Server sends a terminator sequence at the end. when the client detects this terminator, it starts to process....

(iphone) how to force close socket stream?

I use the following code to connect to server and handle events.
almost copy-paste of http://www.devx.com/wireless/Article/43551
I want to force close the stream before NSStreamEventEndEncountered.
Documentation is lacking and having hard time to figure out how to force close the streams associated with connection. (or close underlying socket if I have to)
Thank you
-(void) connectToServerUsingStream:(NSString *)urlStr
portNo: (uint) portNo {
if (![urlStr isEqualToString:#""]) {
NSURL *website = [NSURL URLWithString:urlStr];
if (!website) {
NSLog(#"%# is not a valid URL");
return;
} else {
[NSStream getStreamsToHostNamed:urlStr
port:portNo
inputStream:&iStream
outputStream:&oStream];
[iStream retain];
[oStream retain];
[iStream setDelegate:self];
[oStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream open];
[iStream open];
}
}
}
and handles event
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSLog(#"stream event %d", eventCode) ;
if( stream == iStream ) NSLog(#"on input stream");
else if( stream == oStream ) NSLog(#"on output stream");
else NSLog(#"on unknown stream identifier") ;
switch(eventCode) {
case NSStreamEventEndEncountered:
{
NSLog(#"stream ended; will be closed") ;
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil; // stream is ivar, so reinit it
break;
}
case NSStreamEventErrorOccurred:
NSLog(#"stream error") ;
break ;
case NSStreamEventHasBytesAvailable:
//TODO: read here
break ;
case NSStreamEventNone:
NSLog(#"stream null event") ;
break ;
case NSStreamEventOpenCompleted:
NSLog(#"stream is now open") ;
break ;
case NSStreamEventHasSpaceAvailable:
//write here
break ;
}
}
Execute the following method on the thread/runloop that the stream was scheduled on:
- (void)closeStream:(NSStream *)stream {
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil;
}

ios Socket Stream problem

I am using tcp connection to connect a server using ip and port. I can write and read stream on it. my problem is when I turn off server .app stop with "EXC_BAD_ACCESS" can anyone help me?
this is connect code:
-(void) connectToServerUsingStream:(NSString *)urlStr
portNo: (uint) portNo {
if (![urlStr isEqualToString:#""])
{
NSURL *website = [NSURL URLWithString:urlStr];
if (!website)
{
NSLog(#"%# is not a valid URL");
return;
}
else
{
[NSStream getStreamsToHostNamed:urlStr
port:portNo
inputStream:&iStream
outputStream:&oStream];
[iStream retain];
[oStream retain];
[iStream setDelegate:self];
[oStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream open];
[iStream open];
}
}
}
and this is stream event delegate:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (data == nil)
{
data = [[NSMutableData alloc] init];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len)
{
[data appendBytes:(const void *)buf length:len];
int bytesRead;
bytesRead += len;
}
else
{
NSLog(#"No data.");
return;
}
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"From server: %#",str);
[str release];
[data release];
data = nil;
break;
}
case NSStreamEventErrorOccurred:
{
NSError *theError = [stream streamError];
NSLog(#"Error reading stream! ,Error %i: %#",[theError code], [theError localizedDescription]);
[self disconnect];
[self connectToServerUsingStream:kHostIP portNo:kPort];
break;
}
case NSStreamEventHasSpaceAvailable:
{
if(stream == oStream && !isDataSent)
{
isDataSent = YES;
[self writeToServer:#"HI"];
}
break;
}
}
}
You should probably implement NSStreamEventEndEncountered case and close / release the stream.
What logging messages are you getting so you can see which parts of your code get called?
Have you tried setting some breakpoints and then stepping through to see the exact point of failure and also then inspect the objects in case you aren't retaining/releasing properly?
What other debugging steps have you taken so far?
Try adding the following linker flags:
OTHER_LDFLAGS = -lz -lxml2 -ltidy -ObjC
To your project.