Re: Reading a string from a socket

  • I'm looking for a simple way to read a string from a specific TCP
    host & port.  I've implemented the server, and it works correctly
    when I access it via telnet, and now I'm trying to implement a simple
    client.

    Here's my current code:
      NSSocketPort* socket = [[[NSSocketPort alloc]
    initRemoteWithTCPPort:4777 host: @"127.0.0.1"] autorelease];
      if (socket == nil) { NSLog(@"Unable to create NSSocketPort"); }
      else if ([socket socket] == -1) { NSLog(@"NSSocketPort contains
    invalid file descriptor"); }
      else {
        NSFileHandle* file = [[[NSFileHandle alloc]
    initWithFileDescriptor:[socket socket] closeOnDealloc:YES] autorelease];
        NSString message = [[NSString alloc] initWithData:[file
    readDataToEndOfFile] encoding:NSUnicodeStringEncoding];
        ...
      }

    I found an online discussion somewhere suggesting something like this
    would work, but unfortunately I find that, invariably, "[socket
    socket]" evaluates to -1.  (I was confused for awhile that when I
    used a bad host name, "[socket socket]" would evaluate to 0, which
    represents STDIN.  Then I noticed that "socket" was nil -- hence the
    additional check.  Note that the init documentation doesn't bother to
    mention that the result may be nil.)

    I believe this line from the init documentation describes the problem
    with my code: "A connection is not opened to the remote host until
    data is sent."  I think that means that "[socket socket]" won't given
    me a meaningful result until I send something.  Unfortunately, I
    don't know how to send something until I can get a meaningful result...

    Any suggestions?  Can I make this code work?  Or should I be trying a
    different approach (note that I don't want to change the server in
    any way)?  Perhaps I'd be better off using lower-level APIs?

    Thanks,
    Dan
  • On Jan 18, 2008 7:07 PM, Daniel Smith <dlsmith...> wrote:

    > Any suggestions?  Can I make this code work?  Or should I be trying a
    > different approach (note that I don't want to change the server in
    > any way)?  Perhaps I'd be better off using lower-level APIs?

    Take a look at http://developer.apple.com/documentation/Cocoa/Conceptual/Streams/Articles/
    NetworkStreams.html


    Hamish
  • On Jan 18, 2008, at 2:01 PM, Hamish Allan wrote:

    > On Jan 18, 2008 7:07 PM, Daniel Smith <dlsmith...> wrote:
    >
    >> Any suggestions?  Can I make this code work?  Or should I be trying a
    >> different approach (note that I don't want to change the server in
    >> any way)?  Perhaps I'd be better off using lower-level APIs?
    >
    > Take a look at http://developer.apple.com/documentation/Cocoa/
    > Conceptual/Streams/Articles/NetworkStreams.html
    >
    > Hamish

    Thanks for that suggestion.  I had looked into
    NSStream:getStreamsToHost previously, and forgot to mention why I
    avoided it: I'm using Bonjour to locate the server, which gives me an
    NSNetService.  The address information I get from
    NSNetService:addresses is already encoded as a sockaddr struct.
    While my example didn't demonstrate it, what I was ultimately trying
    to use is the NSSocketPort:initRemoteWithProtocolFamily:...
    constructor, because it takes a sockaddr as input.  Alternatively, I
    would need to be able to map from the sockaddr to an IP address and
    port in a format that NSStream:getStreamsToHost or some other method
    understands.

    I'm not wild about the idea of turning an IP address encoded as bytes
    into a string, just so that I can conform to an interface (which will
    promptly parse my string into bytes again); and while NSNetService
    has a hostName method, I don't like the idea of generating another
    DNS query just to resolve a host name that has already been resolved,
    either.

    —Dan
  • On Jan 18, 2008, at 2:17 PM, Daniel Smith wrote:

    > On Jan 18, 2008, at 2:01 PM, Hamish Allan wrote:
    >
    >> On Jan 18, 2008 7:07 PM, Daniel Smith <dlsmith...> wrote:
    >>
    >>> Any suggestions?  Can I make this code work?  Or should I be
    >>> trying a
    >>> different approach (note that I don't want to change the server in
    >>> any way)?  Perhaps I'd be better off using lower-level APIs?
    >>
    >> Take a look at http://developer.apple.com/documentation/Cocoa/Conceptual/Streams/Articles/
    NetworkStreams.html

    >>
    >> Hamish
    >
    > Thanks for that suggestion.  I had looked into
    > NSStream:getStreamsToHost previously, and forgot to mention why I
    > avoided it: I'm using Bonjour to locate the server, which gives me
    > an NSNetService.  The address information I get from
    > NSNetService:addresses is already encoded as a sockaddr struct.
    > While my example didn't demonstrate it, what I was ultimately trying
    > to use is the NSSocketPort:initRemoteWithProtocolFamily:...
    > constructor, because it takes a sockaddr as input.  Alternatively, I
    > would need to be able to map from the sockaddr to an IP address and
    > port in a format that NSStream:getStreamsToHost or some other method
    > understands.

    If you're using NSNetServices to discover hosts, can't you just use
    this method:

    - (BOOL)getInputStream:(NSInputStream **)inputStream outputStream:
    (NSOutputStream **)outputStream;

    defined in NSNetServices.h to pick up the streams? This completely
    forgoes any resolution and just fills in the streams parameters for you.

    .chris

    --
    Chris Parker
    Cocoa Frameworks
    Apple Inc.
  • On Jan 18, 2008, at 4:30 PM, Chris Parker wrote:

    >
    > On Jan 18, 2008, at 2:17 PM, Daniel Smith wrote:
    >
    >> On Jan 18, 2008, at 2:01 PM, Hamish Allan wrote:
    >>
    >>> On Jan 18, 2008 7:07 PM, Daniel Smith <dlsmith...> wrote:
    >>>
    >>>> Any suggestions?  Can I make this code work?  Or should I be
    >>>> trying a
    >>>> different approach (note that I don't want to change the server in
    >>>> any way)?  Perhaps I'd be better off using lower-level APIs?
    >>>
    >>> Take a look at http://developer.apple.com/documentation/Cocoa/
    >>> Conceptual/Streams/Articles/NetworkStreams.html
    >>>
    >>> Hamish
    >>
    >> Thanks for that suggestion.  I had looked into
    >> NSStream:getStreamsToHost previously, and forgot to mention why I
    >> avoided it: I'm using Bonjour to locate the server, which gives me
    >> an NSNetService.  The address information I get from
    >> NSNetService:addresses is already encoded as a sockaddr struct.
    >> While my example didn't demonstrate it, what I was ultimately
    >> trying to use is the NSSocketPort:initRemoteWithProtocolFamily:...
    >> constructor, because it takes a sockaddr as input.  Alternatively,
    >> I would need to be able to map from the sockaddr to an IP address
    >> and port in a format that NSStream:getStreamsToHost or some other
    >> method understands.
    >
    > If you're using NSNetServices to discover hosts, can't you just use
    > this method:
    >
    > - (BOOL)getInputStream:(NSInputStream **)inputStream outputStream:
    > (NSOutputStream **)outputStream;
    >
    > defined in NSNetServices.h to pick up the streams? This completely
    > forgoes any resolution and just fills in the streams parameters for
    > you.
    >
    > .chris
    >
    > --
    > Chris Parker
    > Cocoa Frameworks
    > Apple Inc.

    I must have tried that, too, but it was awhile ago and I don't recall
    what happened.  I'll investigate and let you know.

    —Dan
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today