Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
General
GeneralPortable MacsHardwareNetworking
Applications
Mac ApplicationsEudoraFirefox / MozillaInternet ExplorerOutlook ExpressMS OfficeEntourageExcelPowerPointWordVirtual PCMedia PlayerOther MS Products
Programming
Mac ProgrammingCodeWarriorPerl
Country Specific
Australian Mac GroupUK Mac Group

Mac Forum / Programming / Mac Programming / June 2005



Tip: Looking for answers? Try searching our database.

Sockets in Cocoa

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Ulrich Hobelmann - 18 Jun 2005 16:13 GMT
Hi, I'm kind of lost in between the sockets.
There's tons of connection classes, Ports, Handles, Protocols etc....

I just want to open a TCP connection to some server and be able to
send and receive data (i.e. cstrings or bytes) to it.  A pipe
would be ok too, so I can talk to a local task.

My futile attempt included creating a NSSocketPort
(initRemoteWithTCPPort:21 host:@"localhost"), but the socket (file
destriptor is -1 (error??).  The documentation says, the socket
only connects when data is sent.  Ok.

So I create an NSFileHandle (initWithFileDescriptor:), register
for notifications, call waitForDataInBackgroundAndNotify on the
file handle and wait.  But now the whole thing blows up, I guess
because the file handle wasn't even valid after all.

So: how DO I create a simple socket connection?  How do I get
notified when data is there and send stuff back?  The context is a
Cocoa GUI program (for now just textfield, send button, and
message field for server responses).

Signature

Don't let school interfere with your education. -- Mark Twain

Sherm Pendley - 18 Jun 2005 17:40 GMT
> Hi, I'm kind of lost in between the sockets.
> There's tons of connection classes, Ports, Handles, Protocols etc....

FWIW, Objective-C Protocols have *nothing* to do with networking.

> I just want to open a TCP connection to some server and be able to
> send and receive data (i.e. cstrings or bytes) to it.  A pipe would be
> ok too, so I can talk to a local task.
>
> My futile attempt included creating a NSSocketPort

Stop. NSPort and its descendants are used for sending Mach messages.
NSSocketPort is for sending Mach messages over BSD socket, not for
sending arbitrary network traffic.

> So I create an NSFileHandle (initWithFileDescriptor:), register for
> notifications, call waitForDataInBackgroundAndNotify on the file
> handle and wait.  But now the whole thing blows up, I guess because
> the file handle wasn't even valid after all.

Now you're on the right track. How did you create the file descriptor
you passed to the initializer? For socket communications, you should be
creating it with the socket() function - "man socket" for details.

sherm--
Ulrich Hobelmann - 18 Jun 2005 21:39 GMT
>>Hi, I'm kind of lost in between the sockets.
>>There's tons of connection classes, Ports, Handles, Protocols etc....
>
> FWIW, Objective-C Protocols have *nothing* to do with networking.

Oh yeah, I know that :)

It's just that there are some protocols that start with NSURL, so
I thought they might be relevant...

>>I just want to open a TCP connection to some server and be able to
>>send and receive data (i.e. cstrings or bytes) to it.  A pipe would be
[quoted text clipped - 5 lines]
> NSSocketPort is for sending Mach messages over BSD socket, not for
> sending arbitrary network traffic.

"NSSocketPort can be used as an endpoint for distributed object
connections or raw messaging."  says the documentation.

At least I thought the mighty Cocoa would have some builtin socket
functions, so I guessed it would be that one.

>>So I create an NSFileHandle (initWithFileDescriptor:), register for
>>notifications, call waitForDataInBackgroundAndNotify on the file
[quoted text clipped - 4 lines]
> you passed to the initializer? For socket communications, you should be
> creating it with the socket() function - "man socket" for details.

Yes, I actually have some socket() wrappers written in C.  If
there are no socket functions in Cocoa, I'll use them and wrap
them in an NSFileHandle.

Thanks.

Signature

Don't let school interfere with your education. -- Mark Twain

Michael Ash - 18 Jun 2005 20:40 GMT
> Hi, I'm kind of lost in between the sockets.
> There's tons of connection classes, Ports, Handles, Protocols etc....
[quoted text clipped - 7 lines]
> destriptor is -1 (error??).  The documentation says, the socket
> only connects when data is sent.  Ok.

Is port 21 open on localhost?

> So I create an NSFileHandle (initWithFileDescriptor:), register
> for notifications, call waitForDataInBackgroundAndNotify on the
[quoted text clipped - 5 lines]
> Cocoa GUI program (for now just textfield, send button, and
> message field for server responses).

As stated in another post, NSSocketPort is not meant for this kind of
thing. I've heard of people using it, so it's possible to make it work,
but it's really not recommended.

If you don't need to support 10.2 and under (and you really shouldn't),
then check out the NSStream APIs. They're very nice for sockets work if
you want to connect to a remote port, and initiating the connection is
simple.

If you want your code to be a server and listen for a connection, then you
can't use NSStream directly. I believe the most direct path is to use
CFSocket to listen for connections, then create a CFStream from that, and
CFStream is toll-free bridged to NSStream.

There are also plenty of non-Cocoa alternatives, of course. Plain BSD
sockets is an obvious choice, and there's also a fairly wide selection of
Objective-C sockets classes, with a list here:

http://www.cocoadev.com/index.pl?SocketClasses
Ulrich Hobelmann - 18 Jun 2005 21:46 GMT
> Is port 21 open on localhost?

Of course, that's why I chose it.  Nicely readable text protocol ;)

> If you don't need to support 10.2 and under (and you really shouldn't),
> then check out the NSStream APIs. They're very nice for sockets work if
[quoted text clipped - 5 lines]
> CFSocket to listen for connections, then create a CFStream from that, and
> CFStream is toll-free bridged to NSStream.

I'll probably have an extra task running (written in C, portable
Unix code), so I'll just talk to it over a socket or pipe.  My
main problem is how to integrate the stream into the Cocoa event
model (because select() would block and so I wouldn't respond to
Cocoa events anymore).  Well, I hope the file handle or Stream
approach works; shouldn't be impossible... :)

Signature

Don't let school interfere with your education. -- Mark Twain

Michael Ash - 19 Jun 2005 11:24 GMT
>> Is port 21 open on localhost?
>
> Of course, that's why I chose it.  Nicely readable text protocol ;)

It's the programming equivalent of asking the user if their computer is
plugged in. Silly, but the simple stuff ends up being the problem
surprisingly often.

>> If you don't need to support 10.2 and under (and you really shouldn't),
>> then check out the NSStream APIs. They're very nice for sockets work if
[quoted text clipped - 12 lines]
> Cocoa events anymore).  Well, I hope the file handle or Stream
> approach works; shouldn't be impossible... :)

NSFileHandle should do fine for integrating your socket into the runloop.
CFSocket is also good for that if you really want to use the BSD sockets
API everywhere possible.

You could also run your sockets stuff using select() in another thread if
you really want to keep everything nice and POSIXy.
Ulrich Hobelmann - 19 Jun 2005 13:30 GMT
> NSFileHandle should do fine for integrating your socket into the runloop.
> CFSocket is also good for that if you really want to use the BSD sockets
> API everywhere possible.

Yes, works nicely :)

> You could also run your sockets stuff using select() in another thread if
> you really want to keep everything nice and POSIXy.

Well, since it seems I have to call
waitForDataInBackgroundAndNotify again and again (and thus create
and kill threads all the time) I might actually roll my own there,
select()ing and posting notifications on my own...  But for now
it's fine.

Signature

Don't let school interfere with your education. -- Mark Twain

David Phillip Oster - 18 Jun 2005 22:20 GMT
> Hi, I'm kind of lost in between the sockets.
> There's tons of connection classes, Ports, Handles, Protocols etc....
>
> I just want to open a TCP connection to some server and be able to
> send and receive data (i.e. cstrings or bytes) to it.  A pipe
> would be ok too, so I can talk to a local task.

You are in luck. Apple just released sample code that demonstrates
how to do exactly what you are trying to do.

Look at:

http://developer.apple.com/samplecode/CocoaSOAP/CocoaSOAP.html

Pay particular attention to TCPServer.m and SOAPClient.m (which
depends heavily on NSURLResponse to actually read the data.

Note that this example gives the source code for a miniature, but functional,
http server. This does do SOAP, but there is an easier way to do SOAP with
Macintosh.

this may also be useful.

http://developer.apple.com/samplecode/XcodeClientServer/XcodeClientServer.html

Of course, if you can use SOAP or XML-RPC, Apple already provides an
appleEvent bridge, so just by changing the destination from another
program on your local machine, to one on a remote machine, AESend()
will take care of marshalling your arguments and unmarshalling the
return value.

See:

http://developer.apple.com/documentation/AppleScript/Conceptual/soapXMLRPC/

The web page is Carbon, but the translation to Cocoa is obvious.

If all you need is SMTP client support, NSMailDelivery is even easier:

<file:///Developer/ADC%20Reference%20Library/documentation/AppleApplications/Reference/MessageFrameworkReference/Classes/NSMailDelivery/index.html>

Note that URL is to documentation that is already on your machine.

There is a trick to getting NSMailDelivery to work: you must explicitly add
Message.framework to your project, your program will mysteriously do nothing.
Unlike most of the Cocoa frameworks, it isn't inside the Cocoa umbrella, so
you don't get it by default.

Also, don't forget that libcurl is available on Mac OS:
<http://curl.oc1.mirrors.redwire.net/>

Signature

David Phillip Oster

Matthew Barnes - 25 Jun 2005 23:53 GMT
> Now you're on the right track. How did you create the file descriptor
> you passed to the initializer? For socket communications, you should
> be
> creating it with the socket() function - "man socket" for details.

Apparently, I have started out on the same track Ulrich did at the
beginning. I am writting a chat client for a not so known client
with a VERY basic protocol already set in place. At first, I was
reading Cocoa In a Nutshell and following the Networking chapter
pretty closely. Nothing really worked so now I'm reading through
Unix Network Programming.

I just got through going through the streams documentation on
Apple.com, but haven't gotten anything to work. Obviously I don't
have much experience with this, but figured it wouldn't be hard to
catch on since I wrote a client for the same protocol a month ago on
Windows.

After reading this thread, and looking up CFSocket, I don't think
that will work for me unless there's a way to connect to various
ports. Also, I think NSOutputStream isn't working because it isn't
using a raw socket. Like I said, I'm not experienced so what do I
know.

Should I just stick to socket() used in Unix Network Programming?

* posted via http://www.mymac.ws
* please report abuse to http://xinbox.com/mymac
Chris Hanson - 26 Jun 2005 01:43 GMT
> After reading this thread, and looking up CFSocket, I don't think
> that will work for me unless there's a way to connect to various
> ports. Also, I think NSOutputStream isn't working because it isn't
> using a raw socket. Like I said, I'm not experienced so what do I
> know.

I'm not sure what you mean by "raw socket" here.

If you can require Panther or later, I strongly recommend you take
another look at NSInputStream and NSOutputStream for TCP
communications.  It's very easy to use once you understand the way it
fits together.

Here's the 30-second summary, written off the top of my head:

(1) Use +[NSStream getStreamsToHost:port:inputStream:outputStream:] to
get an NSInputStream and an NSOutputStream to the server you want to
communicate with.  Be sure to retain them, since they're returned to
you autoreleased.  (After all, they come from a method that isn't an
alloc, copy, or retain method.)

(2) Set your controller object to be your input stream and output
stream's delegate.  This means that it will get callbacks for events
that occur on each of the streams via its -stream:handleEvent: method.

(3) Schedule each stream in the current runloop in the default mode.  
This means that your streams' operations will be asynchronous, and that
you don't need to worry much about them blocking execution of your
application as long as you handle the delegate callbacks appropriately.

(4) For your input stream, handle the following events in your
controller's -stream:handleEvent: method:
NSStreamEventHasBytesAvailable (only read when you get one of these,
and only read the number of bytes actually available - you can ask the
stream for this info), NSStreamEventEndEncountered (e.g. the other side
closed the connection), NSStreamEventErrorOccurred.

(5) For your output stream, handle the following events in your
controller's -stream:handleEvent: method: NSStreamEventOpenCompleted
(don't try to write before you get this),
NSStreamEventHasSpaceAvailable (write when you get one of these, and
don't write again until you get another one),
NSStreamEventErrorOccurred.

(6) Open your streams.

(6) When you're done, close your streams and release them.

There may be more you need to do, or I may have gotten the steps
slightly wrong; after all, this is off the top of my head.  So check
the documentation here:
<http://developer.apple.com/documentation/Cocoa/Conceptual/Streams/index.html>

Fundamentally,

streams provide you with a callback-based system that you can use to
read and write network data asynchronously.  It might be a little more
work than you're expecting if you were planning on working
synchronously (e.g. write something, read something, write something,
read something) since you'll have to implement a basic queuing system
and deal with incomplete reads and writes, but once you build some
basic infrastructure around it, it'll be very powerful.  And it
integrates with Cocoa's run loop mechanism and uses the delegate
pattern, meaning you don't have to do learn a separate event-handing or
registration system.

 -- Chris
Geir-Tore Lindsve - 29 Jun 2005 23:03 GMT
A little follow up on this issue.

In may, I set up a small game client which communicates with a server
by using NSInputStream and NSOutputStream. That works well, but now I
have decided to set it up for another "environment".

I'm planning to rewrite the game to be independent of that server. What
I then are planning are to give the user the choice of starting a game,
or connect to a existing game when the game opens. I guess that the
current use of NSInputStream/NSOutputStream works for connecting to a
existing game.

But how can I set up a game to wait for connections from another client
(which uses NSInputStream/NSOutputStream), and the set up
input/outputstreams to that client?

Any advice?
Signature

Mvh
Geir-Tore Lindsve

David Phillip Oster - 30 Jun 2005 04:32 GMT
> A little follow up on this issue.
>
[quoted text clipped - 11 lines]
> (which uses NSInputStream/NSOutputStream), and the set up
> input/outputstreams to that client?

<http://developer.apple.com/samplecode/Cocoa/idxNetworking-date.html>
has some good resources for you. Take a look at:

CocoaSOAP - Demonstrates implementing a SOAP client and server in Cocoa.
at the tcp/ip level, even includes the source  code for a small http
server.

<http://developer.apple.com/documentation/Cocoa/Networking-date.html>
is also useful.

Signature

David Phillip Oster

Michael Ash - 30 Jun 2005 09:28 GMT
> But how can I set up a game to wait for connections from another client
> (which uses NSInputStream/NSOutputStream), and the set up
> input/outputstreams to that client?

As you may have noticed, NSStream doesn't have any APIs to wait for a
connection, only to make a connection to somebody else who's waiting.

However, CFStream allows you to create a stream pair for an arbitrary
native socket, and CFStream and NSStream are bridged. This means that the
main issue is doing the whole listen-and-connect dance, because CFStream
expects you to have already done that. You could do that in a separate
thread using the standard POSIX APIs, or you could use CFSocket to handle
that phase, which has nice runloop integration.

So in summary, CFSocket to listen, CFStream once connected, and then cast
to NSStream and do what you have been doing.
Geir-Tore Lindsve - 01 Jul 2005 00:38 GMT
>> But how can I set up a game to wait for connections from another client
>> (which uses NSInputStream/NSOutputStream), and the set up
[quoted text clipped - 12 lines]
> So in summary, CFSocket to listen, CFStream once connected, and then
> cast to NSStream and do what you have been doing.

Thanks for the tip from both of you. I'll be looking into these.
Signature

Mvh
Geir-Tore Lindsve

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.