problem with NSInputStream on real iPhone - 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.

Related

Can't receive jpeg image from server

I am trying to receive a jpeg image from my c# server. The weird thing is when I run it with the debugger and have a break point anywhere in the method it works perfectly fine. Without a breakpoint then I get this error
Corrupt JPEG data: premature end of data segment
Here is my code
(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSMutableData *data;
data = [NSMutableData new];
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint8_t buffer[1024];
int len;
while([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
[data appendBytes:(const void*)buffer length:sizeof(buffer)];
}
}
UIImage *images = [[UIImage alloc]initWithData:data];
[dvdCover setImage:images];
} break;
case NSStreamEventEndEncountered:
{
//UIImage *images = [[UIImage alloc]initWithData:data];
//[dvdCover setImage:images];
} break;
}
}
hi you can check this code hop it will help you...
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged you can modify it as your reqirement.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
yourImageName.image = [UIImage imageWithData: buffer];
[buffer release];
} break;
It seems you are assuming the whole JPEG image will be transferred in one chunk, and you can just read it with one occurence of 'HasBytesAvailable' event. However you should also consider the case where the JPEG image is transferred to you in multiple chunks.
It might work for you if you set breakpoint, because your code execution might be halted somewhere, and your network buffer had plenty time to receive all bytes of the image. But without breakpoints it might not have time to do so.
Try refactoring your code to accumulate the bytes chunk, and only assume it's done when all bytes have been transferred. (Normally you have to know beforehand how many bytes the image is going to be -- or you can just capture the end of stream event)

Receive an image on the iPhone (TCP Client)

I'm programming a client on the iPhone. I want to send some strings, and receive an image from the server.
I found this tutorial (http://www.devx.com/wireless/Article/43551), it has been very useful. It works if I want to receive strings, but now I want to receive an image, and I can't make it work.
This is my code when the iPhone receives data. It's a mix made with the tutorial and this answer from JeremyP (http://stackoverflow.com/questions/4613218):
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable: {
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[102400];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:102400];
if(len) {
[data appendBytes:(const void *)buf length:len];
// Recibir img
uint8_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [iStream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail
}
if (totalBytesRead < sizeof size) {
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [iStream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: [buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size) {
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else {
[buffer setLength: size];
}
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
[data release];
data = nil;
}
else {
NSLog(#"No data.");
}
} break;
}}
It doesn't work... could you help me?
Well, I made it work this way, but I'm no sure if there's a better way.
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
}
} break;
}}
With this method, the received image must be smaller than max_size.
If you know a better way to do this, please let me know! ;)
If all you want to do is download an image from the server to display, take a look at this:
https://github.com/michaelkamprath/iPhoneMK/tree/master/Views/MKNetworkImageView
There are a lot of built in functions to the iOS that will handle image downloading for you. That is, if you can encapsulate the entities you want to download as separate URLs (e.g., a web server).
If, however, you are trying to send and receive data across the same TCP connection, I would strongly advise that you change to a more RESTful approach. Partly because it is easier to implement from the client side, partly because you don't have to worry (as much) about the underlying TCP connection.

CFStream IOS Socket communication

how can i clear an CFStream buffer?
Everytime i read from socket there is still data from an old request, i mean complete response to an old request not just a fragment of it.
Am i missing something ?
This is a function i use to initialize the connection:
-(void)openSocketConnection:(UInt32)port: (NSString *)host
{
NSString *hoststring = [[NSString alloc] initWithString:host];
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,(__bridge CFStringRef)hoststring ,
port,&_nnet_readStream,&_nnet_writeStream);
CFWriteStreamCanAcceptBytes(_nnet_writeStream);
CFWriteStreamSetProperty(_nnet_writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFReadStreamSetProperty(_nnet_readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(_nnet_writeStream)) {
NSLog(#"Error Opening Write Socket");
}
if(!CFReadStreamOpen(_nnet_readStream)) {
NSLog(#"Error Opening Write Socket");
}
}
This is a function i use to read data from socket:
BOOL done = NO;
NSMutableString* result = [NSMutableString string];
while (!done)
{
if (CFReadStreamHasBytesAvailable(_nnet_readStream))
{
UInt8 buf[1024];
CFIndex bytesRead = CFReadStreamRead(_nnet_readStream, buf, 1024);
if (bytesRead < 0)
{
CFStreamError error = CFReadStreamGetError(_nnet_readStream);
NSLog(#"%#",error);
} else if (bytesRead == 0)
{
if (CFReadStreamGetStatus(_nnet_readStream) == kCFStreamStatusAtEnd)
{
done = YES;
}
} else
{
[result appendString:[[NSString alloc] initWithBytes:buf length:bytesRead encoding:NSUTF8StringEncoding]];
}
} else
{
done = YES;
}
}
You seem to assume that when you get data from the host on the other end it will always be available all in one go.
I don't know what the underlying protocol is, but in general it's entirely possible that the remote end will try and send 1600 bytes and that you'll get 1500 bytes but then have to wait a few milliseconds (or even seconds) for the next 100 bytes. Meanwhile CFReadStreamHasBytesAvailable would return false and so your code would set your done flag even though you haven't read all the data the server sent.

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.

In iPhone programming, How can i receive image file with TCP/IP from server which has XP os?

I am making image receiver with iPhone.
The server send image file with byte.
and, i tried to make this bytes to image.
But, i can not make image. already, several days past...
i really need your help...
this is source code that i use.
Byte recvBuffer[500];
memset(recvBuffer, '\0', sizeof(recvBuffer));
[iStream read:recvBuffer maxLength:sizeof(recvBuffer)-1];
NSUInteger len = sizeof(recvBuffer);
NSData *webdata = [NSData dataWithBytes:recvBuffer length:len];
imageview.image = [UIImage imageWithData:webdata];
if you give a comment, i will really appriciate! thank you for reading!
badgerr's answer is substantially the one I would use, but since the question is tagged Objective-C the code should really be in Objective-C - omething like the following. Note that over a TCP/IP connection, -read:maxLength: may return before the requested number of bytes has been read.
uint32_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [istream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size)
{
totalBytes+= bytesRead;
bytesRead = [istream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0)
{
totalBytesRead += bytesRead;
}
else
{
// read failure, report error and bail
}
if (totalBytesRead < sizeof size)
{
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [istream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size)
{
totalBytes+= bytesRead;
bytesRead = [istream read: (char*)[buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0)
{
totalBytesRead += bytesRead;
}
else
{
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size)
{
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else
{
[buffer setLength: size];
}
imageView.image = [UIImage imageWithData: buffer];
[buffer release];
I typed the above straight in to SO, so it is not tested or even compiled.
TCP/IP is a protocol which is OS independent, so the fact that you're using XP on the server should not affect anything, aside from potentially using the windows API for socket operations.
Claus Broch is correct in saying that 499 bytes looks a bit small for an image. What I suggest you do instead is first find the total size of the image (in bytes) on the server, then send that value at the beginning of the TCP stream, followed by the image data. On the receiving end, your code should first read this size value, allocate some memory of that size, then read that many bytes into it. You haven't posted your server code, so I can't help with that, but the client could look a little something like:
unsigned int size = 0; //assumes the size is sent as an int
Byte* recvBuffer;
[iStream read:&size maxLength:sizeof(unsigned int)];
recvBuffer = new Byte[size];
memset(recvBuffer, 0, size);
[iStream read:recvBuffer maxLength:size];
NSData *webdata = [NSData dataWithBytes:recvBuffer length:size];
imageview.image = [UIImage imageWithData:webdata];
delete [] recvBuffer;
Edit My inner C++ made me use new and delete. While you can use this in Obj-C using the .mm file suffix, this question is tagged Objective-C. You should use JeremyP's answer, as it also includes error checking and a more reliable way of reading the complete image.