Totally Objects Home Page

Sharing Information over
TCP/IP in Real-time

What's New? Products Totally Objects Downloads Other Downloads Consultancy VAST Training
Educational Discounts See what our clients think Buy News Groups Consultant's Pack Contact Us

 

Requires:

Introduction

Do you ever want your clients to receive live data-feeds from your server? Maybe your clients need to know some current share prices or currency exchange rates. This web page shows you how to use Socket Set to enable clients to register their interest in information on another machine on a TCP/IP network (such as the Internet) so that they will receive updates to that information as they happen. Our example used for explanation is a server wishing to provide a String to a number of clients. The server application will comprise a window containing a single text box. When a client connects to the server it will be sent the contents of the text box (which it displays in a label in a window). Whenever the contents of the text box changes in the server application, the label changes in each client's window.

Building the Server

Load the application 'TobSockets' into your image and create a new application using the VA Organizer and name it, say, 'MyServerApp'. Make 'TobSockets' a prerequisite of 'MyServerApp'.

Create a new visual part 'MyServerWindow' in 'MyServerApp' and open it with the Composition Editor. Connect the 'openedWidget' event of the window to a new method #startServer and connect the 'aboutToCloseWidget' event of the window to a new method #stopServer. Drop a new Text part into the window and call it 'Text', say. Connect its 'string' event to a new method #textStringChanged. Before you create the body of those methods add the instance variable names 'server' and 'semaphores' to 'MyServerWindow'. Then edit the methods so they look like these:

startServer
    "Create a collection to store the Semaphores for each client."
    semaphores := Set new.

    "Create a new Stream Server listening on port 9000"
    server := TobSocketsStreamServer
      address: (TobSocketsAddress host: (TobSocketsHost localHost) portNumber: 9000)
      clientBlock: [:cs | | semaphore |

        "Client has connected"

        semaphore := Semaphore new.
        semaphores add: semaphore.

        "Keep looping until and exception occurs.
        An exception will occur when the client disconnects."
        [
          [
            "Send the contents of 'Text' to the client."
            cs
              nextPutAll: (self subpartNamed: 'Text') string;
              cr.
            "Wait until 'Text' changes."
            semaphore wait.
            true
          ] when: TobSocketsExceptions::ExTobSockets do: [:sig |
            sig exitWith: false
          ]
        ] whileTrue: [].

        "The client is no longer interested in changes to 'Text'."
        semaphores remove: semaphore
      ].
    "Run the server in the background - we could run multiple servers
    simultaneously in the same image like this."
    server forkAt: (Processor userBackgroundPriority)

stopServer
    server stop

textStringChanged
    semaphores isNil ifTrue: [^ self].

    "Signal each semaphore to give the client the new value"
    semaphores do: [:sem |
      sem signal
    ]

Save the part. Now test the part to start the server. To create a client open an application such as 'telnet' in Windows (from the 'Start' menu select 'Run...', type 'telnet' and press 'OK'). Use it to Connect to your local machine on port 9000. As you type in the server window you should see the text appear in the telnet application window.

If you do need to modify the #startServer method (say, to use a different port number), make sure that you first close the window to stop the server.

Once the server seems to be behaving correctly, close the window and build a standalone application with 'MyServerWindow' set to open at startup. Run the application to check that it runs as it did in the development image.

Building the Client

Create a new application using the VA Organizer and name it, say, 'MyClientApp'. Make 'TobSockets' a prerequisite of 'MyClientApp'.

Create a new visual part 'MyClientWindow' in 'MyClientApp' and open it with the Composition Editor. Connect the 'openedWidget' event of the window to a new method #connectToServer and connect the 'aboutToCloseWidget' event of the window to a new method #disconnectFromServer. Drop a new Label part into the window and call it 'Label', say. Before you create the body of the methods add the instance variable names 'socket' and 'process' to 'MyClientWindow'. Then edit the methods so they look like these:

connectToServer
    "Connect a new socket to the server on port 9000"
    socket := TobSocketsSocket new.
    socket connect: (
      TobSocketsAddress
        host: (TobSocketsHost hostName: 'name.of.machine.running.server')
        portNumber: 9000).

    "'socket' should not time-out when doing #nextLine.
    Instead it should wait until there is something to get."
    socket upToTimeOut: 0.

    "Wait for new data in a background process."
    process := [
      "Loop until the server drops the connection."
      [
        [
          "Read a line of text from the server and display it."
          (self subpartNamed: 'Label') labelString: (socket nextLine).
          true
        ] when: TobSocketsExceptions::ExTobSockets do: [:sig |
          sig exitWith: false
        ]
      ] whileTrue: []
    ] forkAt: (Processor userBackgroundPriority).

aboutToCloseWindow
    socket close.

    process isNil ifFalse: [process terminate]

Save the part and test it while the server application is running. The text that you type in the server window should appear in the label in the client. This web page shows just the basics. It would be easy to extent these ideas further so that Smalltalk objects are exchanged (rather than strings) by incorporating the ObjectSwapper. Or maybe the server could be used to serve many different pieces of information named by the client. You would also probably want to improve the exception handling at client connection to make it more robust.

Here at Totally Objects we are keen to find out the creative ways that you are using our products in your applications. Please email us at ideas@totallyobjects.com to share your ideas.


Back to SocketSet Home Page Back to Totally Objects Home Page