Using the NSStreamEventHasSpace available event, I am trying to write a simple NSString to to an NSOutputStream. Here is the contents of that event:
uint8_t *readBytes = (uint8_t *)[data mutableBytes];
readBytes += byteIndex; // instance variable to move pointer
int data_len = [data length];
unsigned int len = ((data_len - byteIndex >= 12) ?
12 : (data_len-byteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [output write:(const uint8_t *)buf maxLength:len];
NSLog(#"wrote: %s", buf);
byteIndex += len;
I pretty much took it right from Apple. The data is initialized in my viewDidLoad method with
data = [NSMutableData dataWithData:[#"test message" dataUsingEncoding:NSUTF8StringEncoding]];
[data retain];
The HasSpaceAvailable event is called twice. In the first one, the entire message is written with the characters "N." appended to it. In the second time, NSLog reports that a blank message was written (not null). Then, the EndEncountered event occurs. In that event, I have
NSLog(#"event: end encountered");
assert([stream isEqual:output]);
NSData *newData = [output propertyForKey: NSStreamDataWrittenToMemoryStreamKey];
if (!newData) {
NSLog(#"No data written to memory!");
} else {
NSLog(#"finished writing: %#", newData);
}
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
output = nil;
break;
I also got this from Apple. However, "No data written to memory!" is logged. No errors occur at anytime, and no data appears to have been received on the other end.
I seem to have fixed this by using low level Core Foundation methods instead of higher level NSStream methods. I used this article as a starting point:
http://oreilly.com/iphone/excerpts/iphone-sdk/network-programming.html
It covers input and output streams in great lenghts and has code examples.
Hope this helps.
Related
In my app I'm using NSStreams for client server communication. In the delegate method in event hasbytesAvailable when I'm reading the data its returning null
Case: when the length is 4096 then read is fails and returns nil; Means when the length is equal to buffer size its failing to read, even if I put the maxlength to 4000 and buffer size to 4096, then also whenever 4000 bytes are read its failing. what to do?
Here is the code:
case NSStreamEventHasBytesAvailable:
if (aStream == inputStream) {
uint8_t buffer[4096];
int len;
while ([inputStream hasBytesAvailable]) {
len = (int)[inputStream read:buffer maxLength:sizeof(buffer)];
NSLog(#"\nThe length is -- %d\n",len);
if (len > 0) {
NSData *data = [[NSData alloc] initWithBytes:buffer length:len];
output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
}
}
}
NSLog(#"\n\n%#\n\n",output);
Data read from a network connection will not always be received in the same sized chunks it was sent in. This means the receiver needs to:
Know exactly how much data to expect in a message.
Remember any "left over" data from the current message as that belongs to the next message.
One of the easiest ways of doing this properly is to prefix the message with a byte-count and then only attempt to read that much data from the network connection. That leaves any remaining data in the "network buffer" until the client wants it.
Your code is receiving a string, which will be NUL-terminated, so that means you need to read the data in fixed-sized chunks, check every byte until you find the end-of-string and then tack together the chunks before converting it to a string. You then need to remember any "left over" data for the next message. Complicated stuff, eh?
I'd go with the message size prefix, as that is what pretty much everyone else does.
I think the code is absolutely fine and it should read the data, may be after you've read 4096 bytes there might be some more bytes available and loop continues, and you are initialising the output variable again, So you might be missing it.
Use the following snippet:
if (aStream == inputStream) {
uint8_t buffer[4096];
int len;
NSString* tempOutput = #"";
while ([inputStream hasBytesAvailable]) {
len = (int)[inputStream read:buffer maxLength:sizeof(buffer)];
NSLog(#"\nThe length is -- %d\n",len);
if (len > 0) {
NSData *data = [[NSData alloc] initWithBytes:buffer length:len];
output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tempOutput = [tempOutput stringByAppendingString:output];
// output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
}
}
output = tempOutput;
}
I am getting chunks of NSData sequentially from server, more than approx. 4096 bytes at a time, sequentially. Each received chunk may differ in its size.
What I would like to do, is to append all these bytes somewhere, and at the same time start reading from the beginning of the data, sequentially, 512 bytes at a time maximum.
While searching I've learned about using NSInputStream for this, and here is the code snippet:
uint8_t bytes[512];
UInt32 length;
NSInputStream *stream = [[NSInputStream alloc] initWithData:aData];
[stream open];
while (((length = [stream read:bytes maxLength:512]) > 0)) {
if ([self.inputStreamer isKindOfClass:[PLAudioInputStreamerNoOpenClose class]]) {
[self.inputStreamer hasData:bytes length:length];
}
}
While this just works, the initialized NSInputStream does not seem to allow appending additional bytes after it is initialized, so the only way I could think of is, to initialize NSInputStreams for every chunk of data, and block until it has reached its end, going on to do the same for next chunk of bytes, as the code above does.
Is there any more preferred solution for this kind of task? Any help will be appreciated. Thank you,
You need a 'read and write' stream. NSInputStream is read only and NSOutputStream is write only.
If I were you, I just use a NSMutableData and one int variables for 'current reading position'.
NSMutableData* myData = [[NSMutableData alloc] init];
NSInteger myPos = 0;
[myData appendData:..];
...
// need to check the range (myPos ~ [myData length])
NSData* nextBlockToRead = [NSData dataWithBytesNoCopy:((char*)[myData bytes] + myPos) length:512];
myPos += 512;
I am kind of new to objective-c so please help. i am receiving the image but not completely here is my code.
I am sure that the problems is here and not on the server side, but if you need me to post the code of the server side then ill do that.
uint8_t buf[3000000];
int len = 0;
len = [inputStream read:buf maxLength:3000000];
UIImage* fooo ;
NSMutableData *dataa=[[NSMutableData alloc] initWithLength:0];
do{
len = [inputStream read:buf maxLength:3000000];
if(len>0) current+=len;
}
while (len>-1);
[dataa appendBytes: (const void *)buf length:current];
fooo = [[UIImage alloc] initWithData:dataa];
[inputStream close];
[outputStream close];
server side
String FilePath=xxxxx.jpeg";
System.out.println (FilePath);
File file1=new
File(xxxxxx\\38.jpeg");
long v=file1.length();
byte [] mybytearray = new byte [(int)file1.length()];
FileInputStream fis = new
FileInputStream(FilePath);
BufferedInputStream bis = new
BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = connectionSocket.getOutputStream();//outpustream
System.out.println("Sending...");
os.write(mybytearray,0,mybytearray.length);
System.out.println("Sent");
os.flush();
Every time when stream comes you creating a new data and try to append.. but actually you are not appending all data to one data object you are doing this way NSMutableData *dataa=[[NSMutableData alloc] initWithLength:0]
I will prefer have an instance variable and do like this
if(!_data) {
_data = [[NSMutableData alloc] initWithLength:0];
}
Whole code should be like this, code is from apple documentation
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if(!_data) {
_data = [[NSMutableData data] retain];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[_data appendBytes:(const void *)buf length:len];
// bytesRead is an instance variable of type NSNumber .
[bytesRead setIntValue:[bytesRead intValue]+len];
} else {
NSLog(#"no buffer!");
}
break;
}
You should handle stream events. Stream will not bring data in one big chunk, so that's why we appending data here. Delegate method will be called with an event and you can set check on event.
When you got this event NSStreamEventEndEncountered close your stream object and create uiimage object
switch(NSStreamEventEndEncountered){
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil; // stream is ivar, so reinit it
if (_data!=nil)
UIImage *image = [UIImage imageWithData:_data];
}
I need to convert the contents of a single element in my uint8_t buffer to an NSString so that I can display it to a label on my iPhone app. I read in the contents of buffer OK from a TCP connection. I am not getting the proper encoding so that an element's value can be displayed correctly. For example, if buffer[4] has the contents of 0xFD or 253, how do I best get that transferred to the label? (The label is data1) Or is there a much simpler way? Thanks.
uint8_t buffer[64];
uint8_t tinybuffer[1];
int len;
// Read in contents from TCP connection, log dump, and display to label.
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
// Log dump
for(int i = 0; i < len; i++) {
NSLog(#"Returning byte %d : %x", i, buffer[i]);
}
NSLog(#"Finished Reading");
// Get data to the screen.
tinybuffer[0] = buffer[4];
NSString *str1 = [[NSString alloc] initWithBytes:tinybuffer length:1 encoding:NSUTF8StringEncoding];
_data1.text = str1;
NSString *str1 = [NSString stringWithFormat:#"%d", tinybuffer[0]];
should do what you want.
I have a file that contains in the very first byte of data a number. In this case that number is 32. I have used a hex editor to confirm that (in hex) the value is "20" which equals 32 in decimal.
Can someone point me in the right direction of how to read it out of the file. I have tried about 6 different ways all of which have failed.
Lots of different ways. Here's one:
NSData *data = [NSData dataWithContentsOfFile:filename];
if ([data length] > 0)
{
const uint8_t *bytes = (const uint8_t *)[data bytes];
uint8_t byte = bytes[0];
NSLog(#"%d", byte);
}
or another:
NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:filename];
[stream open];
NSInteger bufferLen = 1;
uint8_t buffer[bufferLen];
NSInteger count = [stream read:buffer maxLength:bufferLen];
[stream close];
if (count > 0)
{
NSLog(#"%d", buffer[0]);
}