discuss-gnustep
[Top][All Lists]
Advanced

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

Re: a simple program


From: Richard Frith-Macdonald
Subject: Re: a simple program
Date: Thu, 16 Aug 2001 20:01:55 +0000

On Thursday, August 16, 2001, at 04:43 PM, Aurelien wrote:

Hi,

I'm new to GnuStep (though I've already written a small graphics app in Cocoa), and I'd like to play a bit with it for server-side programming. In fact, I'm evaluating writing an Obj-C port of the JXTA platform. For that, I'd need some help with networking/multi-threading.

The following program (written in java) is a simple chat server I wrote some time ago for a client. See how small it is (it took ma about an hour to write, test, deploy) !

To me, writing something like this in Obj-C still appears like a challenge...

Prove me wrong, please ;-) In particular, I'd like to know how to deal with the multi-threading part.

First ... you can do GNUstep coding in Java if you want ... we have a Java interface which works
very well and lets you use ObjC classes from Java code and vice versa.

Second ... you have not chosen a 'fair' example. The given task is something where Java is at it's best - so you might expect the Java code to be more compact and easy to write.

That being said, in the spirit of your original code (a quick hack together where you aren't really concerned about stability etc, just want to get something working), I spent half an hour writing
something similar in ObjC.  Please note, disclaimers ...
1. This is not reliable code ... it suffers from the same problems of multiple threads accessing the
same datastructure in an unsafe way that the java code does.
2. This is not good safe code ... it could be written to trap and handle problems more gracefully. 3. This is not well designed code ... it would be written with nice new classes designed with
extensibility and clarity in mind.
4. This really abuses categories for a quick hack ... I wouldn't do that for a real program - but it
allowed me to make the program shorter and perhaps simpler to follow.
5. In a real heavy-duty server, I would avoid the use of threads altogether, I only really used them for simplicity and because you asked for it. As you can see, the use of threading is trivial.


The basic algorithm is the same as in your version.
Two methods are added to the NSFileHandle class ... one to repeatedly accept incoming connections and store their file handles in the clients array, one to run in new threads.

Note ... The macros for autorelease handling are there to prevent memory leaks ... something you don't need to worry about in Java, but something that gives you more control than in Java.

If you did want to make this really robust, you would need to use an NSLock to synchronize access to the clients array, in a similar ay to that in which you would use 'synchronize'
to make the original java code more reliable.


#include <Foundation/Foundation.h>

NSMutableArray  *clients;

@interface      NSFileHandle (MyCategory)

- (void) accepted: (NSNotification*)notification;
- (void) run;

@end

@implementation NSFileHandle (MyCategory)

- (void) accepted: (NSNotification*)notification
{
  NSDictionary  *userInfo = [notification userInfo];
  NSFileHandle  *hdl;

  hdl = [userInfo objectForKey: NSFileHandleNotificationFileHandleItem];
  if (hdl == nil)
    {
      NSLog(@"Bad handle in 'accepted:' ... terminating.");
      RELEASE(self);
    }
  [clients addObject: hdl];
  [NSThread detachNewThreadSelector: @selector(run)
                           toTarget: hdl
                         withObject: nil];
  [self acceptConnectionInBackgroundAndNotify];
}

- (void) run
{
  CREATE_AUTORELEASE_POOL(pool);
  NSData        *data;

  NS_DURING
    {
      while ([(data = [self availableData]) length] > 0)
        {
          NSEnumerator  *e = [clients objectEnumerator];
          NSFileHandle  *h;

          NS_DURING
            {
              while ((h = [e nextObject]) != nil && h != self)
                {
                  [h writeData: data];
                }
            }
          NS_HANDLER
            {
              NSLog(@"Exception writing to client ... %@", localException);
            }
          NS_ENDHANDLER
        }
    }
  NS_HANDLER
    {
      NSLog(@"Exception reading from client ... %@", localException);
    }
  NS_ENDHANDLER
  [clients removeObjectIdenticalTo: self];
  RELEASE(pool);
}

@end

int main ()
{
  CREATE_AUTORELEASE_POOL(pool);
  NSNotificationCenter  *nc;
  NSFileHandle          *listener;

  clients = [NSMutableArray arrayWithCapacity: 16];
  listener = [NSFileHandle fileHandleAsServerAtAddress: nil
                                               service: @"6401"
                                              protocol: @"tcp"];

  nc = [NSNotificationCenter defaultCenter];
  [nc addObserver: listener
         selector: @selector(accepted:)
             name: NSFileHandleConnectionAcceptedNotification
           object: listener];
  [listener acceptConnectionInBackgroundAndNotify];

  [[NSRunLoop currentRunLoop] run];

  RELEASE(pool);
  return 0;
}



reply via email to

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