(iphone) how to force close socket stream? - iphone

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;
}

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.

Socket connection stream opened called two times

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];
}
}

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....

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.

How to read SD card contents through iPad Camera Connection Kit in iOS SDK?

I want to read the SD card contents through iPad Camera Connection Kit in iOS SDK, how to do that ? Any code sample ?
Thanks.
There is no official api to do that. It might be possible on a jailbroken device but not using the official sdk.
Use External Accessory Framework
first you need to register for notifications in view did load-
<code>
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_accessoryDidConnect:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_accessoryDidDisconnect:) name:EAAccessoryDidDisconnectNotification object:nil];
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
</code>
Then you should find the attached accessories -
<code>
_accessoryList = [[NSMutableArray alloc] initWithArray:[[EAAccessoryManager sharedAccessoryManager] connectedAccessories]];
</code>
Then check this is the correct accessory you are looking for -
<code>
for(EAAccessory *obj in _accessoryList)
{
if ([[obj protocolStrings] containsObject:#"com.bluebamboo.p25i"])//if find the accessory(p25) record it
{
[accessoryLabel setText:#"P25mi connected"]; // yup this is correct accessory!
[obj release];
break;
}
}
</code>
Then open a session -
<code>
//if accessory not null
if(accessory)
{
session = [[EASession alloc] initWithAccessory:accessory forProtocol:#"com.bluebamboo.p25i"];//initial session that pair with protocol string
[[session outputStream] setDelegate:self];//set delegate class for output stream
[[session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; //set outputstream loop
[[session outputStream] open]; //open session
[[session inputStream] setDelegate:self];
[[session inputStream] open];
[[session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
</code>
Then the stream delegate will be called -
<code>
//this is a stream listener function that would actived by system while steam has any event
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
switch(streamEvent)
{
case NSStreamEventOpenCompleted:
if(theStream==[session outputStream])//to identify which stream has been opend
{
[self addLabel:#"outputNSStream open;"];
}
else
{
[self addLabel:#"inputNSStream open:"];
}
break;
case NSStreamEventHasBytesAvailable:
//if system has stream data comes in
[self addLabel:#"receiving Data;"];
uint8_t buf2[100];//create a buffer
unsigned int len = 0;
//read buffer commands return actuall length of return data
len = [[session inputStream] read:buf2 maxLength:100];
if (len>0 )
{
if (buf2[4]==0x03&&buf2[5]==0x00)//if two bytes are 0x03 and 0x00, that means print success
{
//display success message
alertMessage = [[UIAlertView alloc] initWithTitle:#"SUCCESS:" message:#"P25i have printed Text successfully" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertMessage show];
[alertMessage release];
[self addLabel:#"received success"];
}
}
[self enableButton];
//operation finished then close all streams and session
[[session outputStream] close];
[[session outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[session outputStream] setDelegate:nil];
[[session inputStream] close];
[[session inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[session inputStream] setDelegate:nil];
[session release];
session = nil;
//[self connectSession];
//switcher2=TRUE;
break;
case NSStreamEventHasSpaceAvailable:
[self addLabel:#" NSStreamEventHasSpaceAvailable"];
if (switcher2)//we send loop mode so application would keep sending data to p25, the switcher2 identify the data has send to P25m
{
//[self addLabel:#"buffer is selected"];
int contentLength=[printContent.text length];
unsigned char buffer[contentLength+7];
buffer[0] = 0X55;
buffer[1]=0x66;
buffer[2]=0x77;
buffer[3]=0x88;
buffer[4]=0x44;//print command
for (int i=5;i<contentLength+5;i++)//add print content
{
buffer[i] =[printContent.text characterAtIndex:i-5];
}
buffer[contentLength+5]=0x0A;
buffer[contentLength+6]=0x0A;
[[session outputStream] write:(const uint8_t *)buffer maxLength:contentLength+7];//send print package
switcher2 =FALSE;
}
break;
case NSStreamEventErrorOccurred:
alertMessage = [[UIAlertView alloc] initWithTitle:#"ERROR:" message:#"NSSTream Error" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertMessage show];
[alertMessage release];
[self enableButton];
[self addLabel:#"NSSTream error"];
break;
default:
break;
}
}
</code>