NSJSONSerialization error - objective-c

I'm trying to send json object to server. But I received an error and I can't fix it.
-(void) connectToHost{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"localhost", 9123, &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]; }
This is my connection to host.
NSDictionary *setUser = [NSDictionary
dictionaryWithObjectsAndKeys:[#"u" stringByAppendingString:my.id],#"id",
#"GET_USER_INFO",#"command",
#"",#"value",
nil];
NSArray *array = [NSArray arrayWithObject:setUser];
jsonDataToSendTheServer = [array JSONRepresentation];
NSLog(#" %# ", jsonDataToSendTheServer);
// array = [NSArray arrayWithObject:jsonDataToSendTheServer];
NSLog(#" %# ", array);
NSLog(#"true or false %c",[NSJSONSerialization
isValidJSONObject: array]);
bytesWritten = [NSJSONSerialization writeJSONObject:array toStream:outputStream options:NSJSONWritingPrettyPrinted error:nil];
and this part is NSJSONSerialization part.
However I got an error.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '***+[NSJSONSerialization writeJSONObject:toStream:options:error:]: stream is not open for writing'
I'm new at objective-c. I can't fix the problem for 3 hours.
=======================================
edit:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent); //this doesn't post in the log when stream opened...
NSLog(#"bytes %i",bytesWritten);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == 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:NSUTF8StringEncoding];
if (nil != output) {
NSLog(#"server said: %#", output);
//[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//[theStream release];
theStream = nil;
break;
case NSStreamEventHasSpaceAvailable:
{
uint8_t *readBytes = (uint8_t *)[_data mutableBytes];
readBytes += bytesWritten; // instance variable to move pointer
int data_len = [_data length];
unsigned int len = ((data_len - bytesWritten >= 1024) ?
1024 : (data_len-bytesWritten));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
//len = [theStream write:(const uint8_t *)buf maxLength:len];
NSLog(#"written %s", buf );
bytesWritten += len;
}
break;
case NSStreamEventErrorOccurred:
{
NSLog(#"no connection");
}
case NSStreamEventNone:
{
//printf("EVENT: None.\n");
break;
}
default:
NSLog(#"Unknown event");
}}
this is my stream: handleEvent: function.
Now after I did add the connectionToHost to delegate I get this kind of error.
012-08-10 16:14:27.302 TaraftarlikOyunu[2274:c07] written P∏◊P‡ˇø
2012-08-10 16:14:28.399 TaraftarlikOyunu[2274:c07] benim bu id 587127341
2012-08-10 16:14:28.399 TaraftarlikOyunu[2274:c07] benim ad Ahmet
2012-08-10 16:14:28.400 TaraftarlikOyunu[2274:c07]
[{"id":"u581277341","command":"GET_USER_INFO","value":""}]
2012-08-10 16:14:28.404 TaraftarlikOyunu[2274:c07] stream event 4
2012-08-10 16:14:28.404 TaraftarlikOyunu[2274:c07] bytes 86
(lldb)
now I don't have an idea that if it buffered or not
=======================EDIT2===============
sorry about this.
the problem probably appears because of this
(void)memcpy(buf, readBytes, len);
I just copy and paste this part of code.
what may be the problem!

The connection method you are using is a little much.
You need to make sure the connection has happened in the delegate
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventHasSpaceAvailable:
NSLog(#\"None!\");
break;
case NSStreamEventOpenCompleted:
NSLog(#\"Stream opened\");
//NOW you can write to the stream

Related

How to make global variable from output socket connection

I'd like to create global variable that will contain answers from socket connection.
This is my code:
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"192.168.0.10", 35000, &readStream, &writeStream);
self.inputStream = objc_unretainedObject(readStream);
self.outputStream = objc_unretainedObject(writeStream);
[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];
}
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(#"Połączono\n");
break;
case NSStreamEventHasBytesAvailable:
if (aStream == self.inputStream) {
uint8_t buffer[1024];
long len;
while ([self.inputStream hasBytesAvailable]) {
len = [self.inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
NSLog(#"%#",output);
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Nie można połączyć\n");
break;
case NSStreamEventEndEncountered:
break;
default:
break;
}
}
I want to make output variable as global so I can use it in other functions. I want to do this because I'd like to create conditions - everytime when I send request, controller answers me and sends ">" symbol so that means it is ready to take another request. I want to create condition that will send only when ">" appears. I have already done RegExp for this but now I have problem with access to output variable outside stream function.
When you declaring something as extern you are telling the compiler the type AND that you will define it somewhere else. In your case you never define your variable.
First, ensure it is defined:
// in .h you would have:
extern NSString* const output; // << declaration
// in .m you would have:
NSString * const output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding]; // << definition

NSOutputStream crashing with Bad Access after write (Objective-c)

I have been trying to get a basic TCP client up and running for my iOS application but have run into a block which i cannot seem to work my head around.
So far i can connect, send a message which is received on the server side but then my app crashes.
Client.h
#import <Foundation/Foundation.h>
#interface Client : NSObject <NSStreamDelegate>
{
NSInputStream *inputStream;
NSOutputStream *outputStream;
}
-(void)initNetworkCommunication;
-(void)send:(NSString*)message;
#end
Client.m
#import "Client.h"
#implementation Client
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"10.0.1.51", 7769, &readStream, &writeStream);
inputStream = ( NSInputStream *)CFBridgingRelease(readStream);
outputStream = ( NSOutputStream *)CFBridgingRelease(writeStream);
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)send:(NSString*)message
{
NSData *data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSUTF8StringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == 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);
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
NSLog(#"End Encountered!");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
theStream = nil;
break;
default:
NSLog(#"Unknown event");
}
}
#end
The output in the console is
2013-10-03 17:01:38.542 MMORPG[6076:70b] stream event 1
2013-10-03 17:01:38.543 MMORPG[6076:70b] Stream opened
2013-10-03 17:01:43.495 MMORPG[6076:70b] stream event 4
2013-10-03 17:01:43.495 MMORPG[6076:70b] Unknown event
It seems like, my message is sent, i receive stream event #4 and then i get a bad access crash. The problem is i have no idea what its having trouble accessing?
Any help would be greatly appreciated!
The problem is that NSStream keeps an assign/unsafe_unretained reference to its delegate. If the delegate is released before the stream is closed and released, the stream will try to call methods on its now deallocated delegate, causing a crash. The solution is to either make sure some other object has a strong reference to the client, preventing its early deallocation, or else make sure you close and release the stream before its delegate is deallocated.

cant read data from tcp port

i have written code for reading data from tcp port 3000
- (BOOL)connect
{
int cIter = 0;
while(cIter++<5)
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
#try{
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)M_CONNECT_HOST, M_CONNECT_PORT, &readStream, &writeStream);
}
#catch (NSException *ex) {
}
if(readStream!=nil && writeStream!=nil)
{
m_sin = (__bridge NSInputStream *)readStream;
m_sout = (__bridge NSOutputStream *)writeStream;
[m_sin setDelegate:self];
[m_sout setDelegate:self];
[m_sin scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[m_sout scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[m_sin open];
[m_sout open];
return true;
}
}
return false;
}
When i write to tcp output stream its working but when i try to read from the tcp input stream its not reading i mean my
[m_sin read:t maxlength:10];
is always returning -1 (where m_sin is my input stream)
And i m passing the data to the tcp port by terminal
please Help me
Implement the handleEvent and check it out the eventCode
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(#"stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (aStream == inputStream) {
// read it in
unsigned int len = 0;
len = [inputStream read:buf maxLength:1019];
buf[len] = '\0';
if(!len) {
if ([aStream streamStatus] != NSStreamStatusAtEnd){
NSLog(#"Failed reading data from peer");
}
} else {
//I am reading UIImage here
NSData *data = [NSData dataWithBytes:(const void *)buf length:1019];
UIImage *image = [UIImage imageWithData:data];
self.transferedimage.image = image;
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"stream ErrorOccurred");
break;
case NSStreamEventEndEncountered:
NSLog(#"stream EndEncountered");
break;
default:
NSLog(#"stream UnKnown");
break;
}
}

How do i know if my client iOS app is connected to the server?

I press the button to connect to the server (TCP), but i don't know whether it connected or not..
Here is that part of the code:
[self connectToServerUsingCFStream:msg portNo:50000];
if(readStream && writeStream)
{
NSString *newText = [[NSString alloc] initWithFormat:#"Connected!! :)"];
statusText.text = newText;
[newText release];
pingButton.hidden = NO;
}
else
{
NSString *newText = [[NSString alloc] initWithFormat:#"Connection unsuccessful :("];
statusText.text = newText;
[newText release];
}
I always get the "Connected!! :)" even if the server is offline :s
The solution for people following the connection method:
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef) urlStr,
portNo,
&readStream,
&writeStream);
if (readStream && writeStream)
{
CFReadStreamSetProperty(readStream,
kCFStreamPropertyShouldCloseNativeSocket,
kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream,
kCFStreamPropertyShouldCloseNativeSocket,
kCFBooleanTrue);
iStream = (NSInputStream *)readStream;
[iStream retain];
[iStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[iStream open];
oStream = (NSOutputStream *)writeStream;
[oStream retain];
[oStream setDelegate:self];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream open];
}
is using the
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
like this:
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *io;
if (theStream == iStream) io = #">>";
else io = #"<<";
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
statusText.text = #"Can not connect to the host!";
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
pingButton.hidden = NO;
statusText.text = #"Connected";
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
if (theStream == iStream)
{
//read data
uint8_t buffer[1024];
int len;
while ([iStream hasBytesAvailable])
{
len = [iStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
NSData *theData = [[NSData alloc] initWithBytes:buffer length:len];
if (nil != output)
{
//do something with data
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
event = #"NSStreamEventHasSpaceAvailable";
if (theStream == oStream)
{
//send data
uint8_t buffer[11] = "I send this";
int len;
len = [oStream write:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSLog(#"Command send");
[oStream close];
}
}
break;
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
statusText.text = #"Can not connect to the host!";
pingButton.hidden = YES;
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
statusText.text = #"Connection closed by the server.";
pingButton.hidden = YES;
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[theStream release];
theStream = nil;
break;
default:
event = #"** Unknown";
}
NSLog(#"%# : %#", io, event);
}
(for all I know!) The credits go to deksa from this post (though i don't know who was the creator, because i've seen this some times on the web, including here o SO). This code was slightly modified by me (pingButton, statusText), if you want the original one go to the link previously mentioned.
The Apple Developer Site has some info on this as well.
Like i've said, I had seen some stuff looking like this on the web, but now i understand that everything that happens after you connect is "automatic"; for instance, if the server is on hold with a read(), the case NSStreamEventHasSpaceAvailable: will be called automatically, and all the code in there will be run.
Now I consider this question answered.
Although you did not provide enough informations, I'd suggest to use ASIHTTPRequest for HTTP, and AsyncSocket for TCP and UDP. If an connection was established, callback methods will be triggered,
I have to say, that my experiences with CFNetwork are very limited, but for me it seems, as if you are just testing, if stream objects exists (if(readStream && writeStream)).
A quick look at CFNetwork Programming Guide: Working with Read Streams tells me, that you have to open it with CFReadStreamOpen(), this function will return an boolean, if it really did open the stream.
if (!CFReadStreamOpen(myReadStream)) {
CFStreamError myErr = CFReadStreamGetError(myReadStream);
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
// Interpret myErr.error as a MacOS error code.
OSStatus macError = (OSStatus)myErr.error;
// Check other error domains.
}
}
BTW:
instead of
NSString *newText = [[NSString alloc] initWithFormat:#"Connected!! :)"];
statusText.text = newText;
[newText release];
you just can write statusText.text = #"Connected!! :)";

NSOuputStream writing multiple times

I'm trying to use the NSStream objects to open and then write and read on a socket but i have a problem.
I don't know how to write on the socket, after i have opened it.
Here is how i have done
1) first openning the socket :
NSURL *website = [NSURL URLWithString:urlStr];
if (!website) {
NSLog(#"%# is not a valid URL");
return;
}
NSHost *host = [NSHost hostWithName:urlStr];
// iStream and oStream are instance variables
[NSStream getStreamsToHost:host port:6667 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];
[iStream open];
[oStream open];
2) Set the loop :
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *io;
if (theStream == iStream) io = #">>";
else io = #"<<";
NSLog(#"stream : %#",theStream);
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
break;
case NSStreamEventHasBytesAvailable:{
event = #"NSStreamEventHasBytesAvailables";
if (theStream == iStream)
{
if(!_data) {
_data = [[NSMutableData data] retain];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [iStream read:buf maxLength:1024];
NSLog(#"Lenght data read : %d", len);
if(len) {
NSData * dataReceived= [[NSString stringWithFormat:#"%s\n", (char *)buf] dataUsingEncoding:NSUTF8StringEncoding];
NSString *s = [[NSString alloc] initWithData:dataReceived encoding:NSUTF8StringEncoding];
NSLog(#"Received _data: \"%#\"\n",s);
} else {
NSLog(#"nothing to read!");
}
}else {
NSLog(#"Not the good stream");
}
break;
}
case NSStreamEventHasSpaceAvailable:{
event = #"NSStreamEventHasSpaceAvailable";
if (theStream == oStream )
{
if(isConnexionCommandSent == NO){
[self sendCommand:#"My connection command"];
isConnexionCommandSent = YES;
}
}
break;
}
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
NSError *theError = [theStream streamError];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[theError localizedDescription]
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
break;
default:
event = #"** Unknown";
}
NSLog(#"%# : %#", io, event);
}
3) then i have a function that is called when I touch a button
- (IBAction)join:(id)sender{
if([oStream hasSpaceAvailable]){
NSLog(#"iStream Status : %d",[iStream streamStatus]);
NSLog(#"oStream Status : %d",[oStream streamStatus]);
[self sendCommand:#"join"];
}else{
NSLog(#"Error command can't be sent");
}
}
-(void) sendCommand:(NSString *) command{
NSLog(#"space : %d",[oStream hasSpaceAvailable]);
if ([oStream hasSpaceAvailable])
{
NSLog(#"Command writen : %s\n",[command cStringUsingEncoding:NSASCIIStringEncoding]);
NSInteger i=[oStream write:(const uint8_t *)[command cStringUsingEncoding:NSASCIIStringEncoding] maxLength:(NSInteger)[command lengthOfBytesUsingEncoding:NSASCIIStringEncoding]];
if (i<0)
{
NSLog(#"erreur lors de l'envoi, status:%i, erreur:%#", [oStream streamStatus], [oStream streamError]);
}
isReadyToSend = NO;
}
else
{
NSLog(#"impossible d'envoyer, status:%i, erreur:%#", [oStream streamStatus], [oStream streamError]);
}
}
But the problem is that when the function join is called, everything goes fine, but the server receives nothing ...
On
NSInteger i=[oStream write:(const uint8_t *)[command cStringUsingEncoding:NSASCIIStringEncoding] maxLength:(NSInteger)[command lengthOfBytesUsingEncoding:NSASCIIStringEncoding]];
i is > 0, so i assume that the writing went well, but on the server nothing is received ... i don't know why ...
Can you help me?
Hey #Ptitaw see this post. I believe there you might find your answer and an easier way to connect and get access automatically to all events (reading, writing, etc..)
Hope I could help :)
A Very very late answer, however, it might be helpful to someone having similar issue.
I think it may be due to data encoding mechanism. Your server might be using UTF-8 encoding and you are sending your data using NSASCIIStringEncoding. Try this:
NSInteger i=[oStream write:(const uint8_t *)[command cStringUsingEncoding:NSUTF8StringEncoding] maxLength:(NSInteger)[command lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];