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];
}
}
Related
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.
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];
}
}
- (void) mailshareClick:(UIButton *)sender
{
NSString *_message = #"wait for set up Mail";
[self waitForWhile:_message];
if ([MFMailComposeViewController canSendMail]){
[NSThread detachNewThreadSelector:#selector(mailFunction) toTarget:self withObject:nil];
}
else {
_message = #"Please set Mail account";
[self remove:_message];
}
}
- (void) mailFunction
{
NSData *data = nil;
if ([self.files.imageArr count]>0)
{
XXImage *single = [self.files.imageArr objectAtIndex:0];
UIImage *image = [[SDImageCache sharedImageCache] imageFromKey:[[single.imagearray objectAtIndex:0] columnImage]];
data = [UIImageJPEGRepresentation(image, 1.0f) retain];
}
[self performSelectorOnMainThread:#selector(mailFinished:) withObject:data waitUntilDone:YES];
[data release];
}
- (void) mailFinished:(NSData *)_data
{
if ([MFMailComposeViewController canSendMail]){
NSData *data = [_data retain];
MFMailComposeViewController *message = [[MFMailComposeViewController alloc] init];
//Title
[message setSubject:self.files.title];
//Body
[message setMessageBody:#"111" isHTML:YES];
[message setToRecipients:[NSArray arrayWithObject:#"mail"]];
//Content
if (data != nil) {
NSString *picStr = [[NSString alloc] initWithFormat:#"%#%#",OutsideWebsite_Normal,self.files.middlePicPath];
[message addAttachmentData: data mimeType: #"" fileName:picStr];
[picStr release];
[data release];
}
message.mailComposeDelegate = self;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
message.modalPresentationStyle = UIModalPresentationFormSheet;
}
[self presentModalViewController:message animated:YES];
[self remove:#"Set up Ok"];
[message release];
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
switch (result) {
case MFMailComposeResultSent:
{
NSLog(#"MFMailComposeResultSent");
break;
}
case MFMailComposeResultSaved:
{
NSLog(#"MFMailComposeResultSaved");
break;
}
case MFMailComposeResultFailed:
{
NSLog(#"MFMailComposeResultFailed");
break;
}
case MFMailComposeResultCancelled:
{
NSLog(#"MFMailComposeResultCancelled");
break;
}
default:
break;
}
[self performSelector:#selector(delayDismissModalView) withObject:nil afterDelay:1];
}
-(void)delayDismissModalView
{
[self dismissModalViewControllerAnimated:YES];
}
After invoke a few times the email method , there will be
[MFSearchResultsViewController hash]: message sent to deallocated instance
Or
[MFMailComposeViewController hash]: message sent to deallocated instance
crash.
As you think of that, what is the MFSearchResultsViewController function.
Whether it can solve the problem,please give me a hand.
You have to setDelegate for the mail controller. If you set the delegate to "self", make sure that the "self" has <MFMailComposeViewControllerDelegate>. If all these can't make it work, make sure you didn't call presentModalViewController twice.
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.
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>