[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Q] NSFileHandle -readDataOfLength behaviour

From: Richard Frith-Macdonald
Subject: Re: [Q] NSFileHandle -readDataOfLength behaviour
Date: Sat, 14 Apr 2007 07:26:02 +0100

On 13 Apr 2007, at 20:03, Vaisburd, Haim wrote:

Richard Frith-Macdonald [mailto:address@hidden wrote:

Tima Vaisburd wrote:

RFM> this method should block until it reads the specified amount of
RFM> (or eof).

but for my stream class I need exactly what read() does, since the
whole idea was to read byte after byte until the record ends (which
determined by the structure of the incoming byte stream, not by the
length passed in the header).

Maybe availableData is what you want.

-availableData does not have a limit. I might be able to use it,
but what I would really want is -readDataOfLength that would not block
until it gets all the length but would return what's available,
blocking only until the first byte comes ( i.e. like read() ).

I think you need to use NSStream for that (or resort to using the read () system call).

I hoped that that's what it should do and was a little disappointed
when you said "block". Since I cannot test on Mac right now (I have one
recently but haven't programmed on it yet) I searched the web for
the proof. Could not find one but I found two other open source
implementations that do what I want and not what you say (see below).

Of course they are not a proof of anything, but raise a concern in my

Could you, please, test the behavior on Mac OSX or just confirm that
done it before?

I just tested again to make sure ...

The test I did was to connect to an smtp server ... which is great because, upon connection the server writes an introductory message and then waits for input, so if your client just tried to read a buffer bigger than the introductory message you get to check the behavior you are interested in.

I modified your test program to do the job ....

#import <Foundation/Foundation.h>

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

void fatal( const char * s )
  char buf[40];
  sprintf( buf, "%s", s );
  perror( buf );

int connectToSocket( const char * addr, int port )
  int socket_fd = socket( AF_INET, SOCK_STREAM, PF_UNSPEC );
  if ( socket_fd == -1 )
    fatal( "socket" );

  struct sockaddr_in sa;

  memset( &sa, 0, sizeof(sa) );
  sa.sin_family = AF_INET;
  inet_aton(addr, &sa.sin_addr);
  sa.sin_port = htons(port);

  if ( connect( socket_fd, (struct sockaddr *)&sa, sizeof( sa ) ) == -1
    fatal( "connect" );

  return socket_fd;

int main(int argc, char ** argv )
    [NSAutoreleasePool new];

    NSLog( @"Connecting to  socket");

    int fd = connectToSocket( "", 25 );

    NSFileHandle * fh = [[NSFileHandle alloc] initWithFileDescriptor:
    NSData * resp = [fh readDataOfLength: 1024];
//    NSData * resp = [fh availableData];

    NSString * response = [[NSString alloc] initWithData: resp
encoding: NSASCIIStringEncoding];

    NSLog( @"got response: \"address@hidden"", response );

    return 0;

As a sanity check I used the netcat (nc) program to read from the smtp port too.

With -readDataOfLength: the test program just blocked producing no output, with -availableData it printed out the smtp server's intro (which is also what netcat did).

Then I went on to the smtp server machine, found the process which was handling the incoming connection from the test program, and killed it. At that point the test program displayed the intro text (because it got an eof when the remote process went away).

So I think the gnustep-base implementation matches the MacOS-X and the other two you found are 'wrong' in the sense that they don't match MacOS behavior (though the documentation is vague enough that either implementation could be viewed as correct).

If you really want to read an individual byte at a time, NSStream is
probably better than NSFileHandle ...
but that's a shockingly inefficient way to do I/O

Do you refer to NSStream or "byte at a time" as being shockingly

Byte at a time.

Of course I meant "byte at a time" in the way getc() macro of standard
IO library does it:
read a block with a system call, scan it with something fast.

That's not what I'd call byte at a time I/O ... getc() uses buffered I/O ... large blocks of data are read and then bytes returned from a buffer. This is not what NSFileHandle does. NSFileHandle reads a block into a buffer and returns the entire buffer ... so if you used readDataOfLength: with a length of 1 (for byte at a time) then each call would allocate a new data object and read a single byte from the operating system ... horribly inefficient.
I guess what you want is something more like this ...

- (int) getByte
  if (offset == length)
      [data release];
      data = [[handle availableData] retain];
      ptr = [data bytes];
      length = [data length];
      offset = 0;
      if (offset == length)
          return -1;
  return ptr[offset++];

reply via email to

[Prev in Thread] Current Thread [Next in Thread]