how can i pass a NSArray over WiFi network? - iphone

can any one provide me a good way to send a NSArray object over wifi network.
I have a code to sent a text message(string) over wifi network.
my code is
Send
- (void) sendText:(NSString *)string {
const uint8_t *message = (const uint8_t *)[string UTF8String];
if (_outStream && [_outStream hasSpaceAvailable])
if([_outStream write:message maxLength:strlen((char *)message)] == -1)
NSLog(#"Failed sending data to peer");
}
Receiver Side
- (void) stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (stream == _inStream) {
// read it in
unsigned int len = 0;
len = [_inStream read:buf maxLength:buffSize];
buf[len] = '\0';
if(!len) {
if ([stream streamStatus] != NSStreamStatusAtEnd)
NSLog(#"Failed reading data from peer");
} else {
NSString *message = [NSString stringWithUTF8String:(char *)buf]; }}
now the message contains my received message...
However i need to send a NSArray object over wifi.can any one help me to do it..

You can use the NSKeyedArchiver to get a NSData object out of your NSArray, the NSData object is just a wrapper for binary data so you can send it over your socket. When you received the data, first transform it back into an NSData object and then use the NSKeyedUnarchiver class to get the array back.

You need mechanism (protocol) that will send elements of array from sender end and in the same way it will receive at the reception end

Related

Can EADemo send http request

Can someone suggest if it is possible to modify the EADemo to send HTTP request (custom header and body). In the project I am working on, the external accessory will be receiving the data using http request.
The method which is for writing on EADemo is
- (void)writeData:(NSData *)data;
Ok, so I found an example which I will be using but instead of GET I will use POST. Below is the example of GET request:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSLog(#"stream:handleEvent: is invoked...");
switch(eventCode) {
case NSStreamEventHasSpaceAvailable:
{
if (stream == oStream) {
NSString * str = [NSString stringWithFormat:
#"GET / HTTP/1.0\r\n\r\n"];
const uint8_t * rawstring =
(const uint8_t *)[str UTF8String];
[oStream write:rawstring maxLength:strlen(rawstring)];
[oStream close];
}
break;
}
// continued ...
}
}
https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Streams/Articles/NetworkStreams.html

Sending C Strings contained in structs through game center

I'm trying to send a message with game center that contains a struct, roughly following Ray Wenderlich's guide. In general sending and receiving messages has been no problem, but once I throw anything with a pointer in I get a bit confused. The goal is to send a few strings and a BOOL over as one message. Relevant code follows:
//myfile.h
typedef enum {
kMessageTypeRandomNumber = 0,
kMessageTypeInterstitial
} MessageType;
typedef struct {
MessageType messageType;
} Message;
typedef struct {
Message message;
char *playerName;
char *scores;
BOOL correct;
char *stat;
} MessageInterstitial;
//myfile.m
- (void)sendData:(NSData *)data {
NSError *error;
BOOL success = [[GCHelper sharedInstance].match sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (!success) {
NSLog(#"Error sending init packet:\n%#",error);
}
}
-(void)send{
MessageInterstitial message;
message.message.messageType = kMessageTypeInterstitial;
message.playerName="test";
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageInterstitial)];
[self sendData:data];
MessageInterstitial * myMessage = (MessageInterstitial *) [data bytes];
printf("player: %s\n",myMessage->playerName); // prints 'player: test' as expected
}
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
Message *message = (Message *) [data bytes];
if(message->messageType == kMessageTypeInterstitial)
{
MessageInterstitial * myMessage = (MessageInterstitial *) [data bytes];
printf("player: %s\n",myMessage->playerName); //prints 'player: ' not expected
}
}
It appears that the data is being saved properly, since I'm able to print it back out right away without issue, but my thinking is that the data is pointing to an address in memory, which would make it so it prints out the correct thing on the sending device, but not the receiving device. That being said, I've got no clue how to fix this, or how i should be sending strings within a struct if that is in fact the case.
Indeed this seems like the problem, the addresses are addresses in the sending device, not receiving device. You can use char arrays instead, and just allocate enough space from the beginning. This way they will be part of the struct:
// those are just examples of course...
typedef struct {
Message message;
char playerName[30];
char scores[30];
BOOL correct;
char stat[15];
} MessageInterstitial;
You have to use a char array, but one thing is that when you create your struct, this char array is randomly filled with all sorts of weird characters, so here's how got rid of those characters :
typedef struct {
char stringToSend[20];
int stringToSendLength;
} myStruct;
// create a Struct and an NSString
myStruct aStruct;
NSString *stringToConvert = #"stringToConvert";
// convert NSString into char array
for (int i = 0; i < stringToConvert.length; i++) {
aStruct.stringToSend[i] = [stringToConvert characterAtIndex:i];
}
aStruct.stringToSendLength = stringToConvert.length; // send string length
// store struct into NSData object
NSData *data = [NSData dataWithBytes:&aStruct length:sizeof(myStruct)];
// retrieve data
myStruct *anotherStruct = (myStruct *)[data bytes];
// convert char array into NSString and only keep part required (without some weird random characters)
NSString *receivedString = [[NSString alloc] initWithBytes:anotherStruct->stringToSend length:anotherStruct->stringToSendLength encoding:NSASCIIStringEncoding];
A little old, but I'll throw in my 2 cents.
When I changed from char * to char string[30] i had to increase the length when I initialised my NSData. In addition, direct assignment of a char array is not possible. You either have to iterate the string and insert the characters one by one, or use strcpy like I did below.
This is how it finally looked like for me:
- (void)sendRandomWord:(NSString*)randomWord{
MessageRandomWord message;
message.message.messageType = kMessageTypeRandomWord;
strcpy( message.randomWord, randomWord.UTF8String );
NSData *data = [NSData dataWithBytes:&message length:sizeof(kMessageTypeRandomWord) + strlen(message.randomWord)*sizeof(char)];
[self sendData:data];
}

how can i send a text to another device only after receiver side instream and outstream setup is done?

i created a network Application to transfer text message between two devices through WiFi network.when i select a device to pair there is a delegate called "TCPServerAcceptCallBack" will trigger in receiver side and it will setup the input and output streams.
but it will take milliseconds to do the setup of streams.whenever i am sending a data from my device there is checking of [_outStream hasSpaceAvailable].i mentioned that instream and outstream setup in receiver side will take milliseconds .so first time the condition will false.i used while loop to stop doing send method before setup is done.but there is a problem that when execution in while loop there is a chance to connection lose in receiver side and also not confident with while loop.
next i created a sleep of 3 millisecond ,it working fine but there is chance of occur error when network is very slow.
i am planning to trigger a delegate from receiver side to sender device at the time of instream and outstream setup is done.so please tell me how can do it (or) provide me any other good way to solve this problem...
My Code...receiver side
case NSStreamEventHasBytesAvailable:
{
if (stream == _inStream) {
// read it in
unsigned int len = 0;
//here the length is assigning..i can send text files only after this below statement is executed.but it will take few minitus.
len = [_inStream read:buf maxLength:buffSize];
buf[len] = '\0';
if(!len) {
if ([stream streamStatus] != NSStreamStatusAtEnd)
NSLog(#"Failed reading data from peer");
} else {
NSString *message = [NSString stringWithUTF8String:(char *)buf];
//Display image from app bundle
NSString *path=[[NSBundle mainBundle] pathForResource:message ofType:#"png"];
if(path !=nil)
{
[imageView setImage:[UIImage imageWithContentsOfFile:path]];
}
else
{
UIImage *image = [UIImage imageNamed:#"no_image.png"];
[imageView setImage:image];
}
// here you do whatever you need with your received NSString *message
[txtUserInput setText:message];
}
}
break;
Sender part..
[- (void) sendText:(NSString *)string {
const uint8_t *message = (const uint8_t *)[string UTF8String];
//waiting up to outStream hasSpaceAvailable
while (![_outStream hasSpaceAvailable]) {
continue;
}
//once outStream hasSpaceAvailable it will send datas.
if (_outStream && [_outStream hasSpaceAvailable])
if([_outStream write:message maxLength:strlen((char *)message)] == -1)
NSLog(#"Failed sending data to peer");
}
#end
Don't use a while loop,that's just wasting CPU cycles. Do it in the callback.

Have been cursing over data packets for 36 hours now, please help!

Ok Here is the problem. I am trying to send through a structure or anything through the apple bluetooth send network packet code. The code to send is below
-(void)sendMessagePacket:(GKSession *)session packetID:(int)packetID withData:(void *)data ofLength:(int)length reliable:(BOOL)howtosend {
static unsigned char networkPacket[maxPacketSize];
const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
if(length < (maxPacketSize - packetHeaderSize)) { // our networkPacket buffer size minus the size of the header info
int *pIntData = (int *)&networkPacket[0];
// header info
pIntData[0] = 10;
pIntData[1] = packetID;
// copy data in after the header
memcpy( &networkPacket[packetHeaderSize], data, length );
NSData *packet = [NSData dataWithBytes: networkPacket length: (length+8)];
if(howtosend == YES) {
[session sendDataToAllPeers:packet withDataMode:GKSendDataReliable error:nil];
} else {
[session sendDataToAllPeers:packet withDataMode:GKSendDataUnreliable error:nil];
}
}
}
If anyone could go through this with a comb and explain what is going on that would be greatly appreciated. Next, the receive code.
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context {
// Caller whenever data is received from the session
unsigned char *incomingPacket = (unsigned char *)[data bytes];
//EXPECTS THAT WHAT IS IN INCOMING PACKET [0] TO BE OF DATA TYPE INTEGER
int *pIntData = (int *)&incomingPacket[0];
int packetTime = pIntData[0];
int packetID = pIntData[1];
static int lastPacketTime = -1;
switch (packetID) {
case NETWORK_COINTOSS:
//DO SOMETHING
break;
case NETWORK_TEXT_EVENT:
NSString *fewMore = (NSString *)&incomingPacket[8];
fewThings *bitMore = &fewMore[peer];
//NSLog(#"Trace Bit More: %#",fewMore);
break;
default:
break;
}
NSInteger lengthBytes = [data length];
NSLog(#"Length of data : %i", lengthBytes);
}
What i am struggling to understnad being a newcome to objective c is how all this works, how do i access the string that i have send as all efforts to log it cause the program to crash.
Below is the code used to start the send:
NSString *bigWord = #"BigWordBigWord";
NSInteger len = [bigWord length];
[self sendMessagePacket:gameSession packetID:NETWORK_TEXT_EVENT withData:bigWord ofLength:(len) reliable:YES];
Any help would be so appreciated. Thank You.
You really need to change the NSString object into either a UTF8 representation to send, or to archive it as an NSData object you send with the full length - you can't just cast an NSString as a C string (either for sending or receiving!!!).
You can get a C string version of NSString using:
const char *sendString = [bigWord cStringUsingEncoding:NSUTF8StringEncoding]
And then get it out of your incoming NSData object with
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
This guy is sending and receiving the string over network just fine. But, I'm also still getting error on the receiving end.
http://discussions.apple.com/thread.jspa?messageID=10215848
At last got it. GKTank is transferring the data using struct, so I placed my string inside the struct and rest is the history.
typedef struct {
NSString *strInfo;
} myInfo;

problem with NSInputStream on real iPhone

I have a problem with NSInputStream. Here is my code:
case NSStreamEventHasBytesAvailable:
printf("BYTE AVAILABLE\n");
int len = 0;
NSMutableData *data = [[NSMutableData alloc] init];
uint8_t buffer[32768];
if(stream == iStream)
{
printf("Receiving...\n");
len = [iStream read:buffer maxLength:32768];
[data appendBytes:buffer length:len];
}
[iStream close];
I try to read small data and it works perfectly on simulator and real iPhone.
If I try to read large data (more than 4kB or maybe 5kB), the real iPhone just can read 2736 bytes and stop.
Why is it? Help me plz!
Merci d'avance!
Your data object needs to be external to your stream handler. It is often the case that when large abounts of data are coming in, you get it in chunks and not all at once. Just keep appending data to it until you receive bytesRead == 0; Then you can close your stream and use the data.
case NSStreamEventHasBytesAvailable: {
NSInteger bytesRead;
uint8_t buffer[32768];
// Pull some data off the network.
bytesRead = [self._networkStream read:buffer maxLength:sizeof(buffer)];
if (bytesRead == -1) {
[self _stopReceiveWithFailure];
} else if (bytesRead == 0) {
[self _stopReceiveWithSuccess];
} else {
[data appendBytes:buffer length:len];
}
Looks like you're creating a new data object every time... perhaps you should be creating & retaining it as a property, and appending to it as you are above.