6.6 Non-blocking sockets

The example here describes a TableServer that keeps track of the name and address of people. 

It consists of a Table object and two objects Producer and Consumer that both are subpatterned from BasicProcess.

The Producer listen on a Socket on port 3000 from new entries and the Consumer listen on a Socket on port 3001 for requests to lookup the name of a person.

The TablesServer is subpatterned from SocketSystem, which defines non-blocking sockets.

Compared to the simple sockets defined here, the accept and receive methods have an extra argument being the calling object and these methods suspend the caller if no object is trying to connect (accept) and if no data is available (receive). The implementation of accept and receive is similar to the implementation of _kbhit and get described here.

TableServer: obj  LIB.SocketSystem.SocketSystem
   Table: obj 
       ...
       insert(nm: ref String.String, adr: ?String.String):
            ...
       lookup(nm: ref String.String) -> adr: ?String.String:
            ...
   Producer: obj BasicProcess("Producer")
           PS: obj Socket
           aProd: ref Socket 
           "Producer:\n".print
           PS.init(3000)
           PS.bind
           PS.listen
           aProd:= PS.accept(Producer)
           cycle
               name: ref String.String
               adr: ref String.String
               answer: reff String.String
               name:= aProd.receive(Producer)
               adr:= aProd.receive(Producer)
               Table.insert(name,Adr)
               answer:= "Inserted: " + name + ":" + adr + "\n"
               answer.print
               aProd.send(answer)
   Consumer: = BasicProcess("Consumer")
           CS: = Socket
           aCons: ref Socket 
           "Producer:\n".print
           CS.init(3001)
           CS.bind
           CS.listen
           aCons:= CS.accept(Consumer)
           cycle
               name: ?String.String
               adr: ?String.String
               answer: ?String.String
               name:= aCons.receive(Consumer)
               adr:= Table.lookup(name)
               answer:= "Address of: " + name + " is " + adr + "\n"
               answer.print
               aCons.send(answer)
   cycle
      Producer.resume
      Consumer.resume
 

The Producer and Consumer objects are shown here.

Producer: obj
   theServer: = LIB.Socket.Socket  -- Ref=none without LIB - adr(Socket)
   theServer.init(3000)
   theServer.connect("localhost")
   cycle
       name: var String.String
       adr: var String.String
       "Type a name: ".print
       name:= LIB.BasicIO.keyboard.ReadLine
       theServer.send(name)
       "Type an address: ".print
       adr:= LIB.BasicIO.keyboard.ReadLine
       theServer.send(adr)
       ("Producer received: " + theServer.receive + "\n").print
   theServer.close;
Consumer: obj
   theServer: = LIB.Socket.Socket  -- Ref=none without LIB - adr(Socket)
   "Consumer:\n".print
   theServer.init(3001)
   theServer.connect("localhost")
   cycle
       name: var String.String
       "Type a name: ".print
       name:= LIB.BasicIO.Keyboard.ReadLine
       theServer.send(name)
       ("Consumer received: " + theServer.receive + "\n").print
   theServer.close;

In this example, the three objects are supposed to run on the same machine as three different processes.

Hello world