Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Ma client server
Last updated at 12:39 am UTC on 17 January 2006

Introduction

Ma client server can help you write a client-server program very easily. It's so easy, in fact, that a server program could be written in one line of code:

	MaServerSocket new listenOn: 12345 answer: [ :requestByteArray | 'Hello world!' asByteArray ]

The framework is actually based on a robust, multi-threaded socket model that John McIntosh shared with me.

In the client-server model, a client sends a request to a server, the server processes the request and sends back a response.

The framework provides two layers interoperation. You choose which layer you want to use and then write two programs. A client program that will send requests to a remote server, which is running the other program to process those requests.

If you choose the lower layer, the "socket layer," you send ByteArray requests and receive ByteArray responses. In the upper layer, the "object request layer" you send arbitrary request objects and get arbitrary objects as responses. The upper layer utilizes the "Ma object serialization" framework to convert the objects to ByteArrays, as well as the lower layer to send those ByteArrays for you.

Using the Socket Layer


Setting up the server

If you just need to send and receive ByteArray's, you write your server program any way you want. Just keep in mind that, somewhere, you're going to want to take-in a ByteArray as input and you must answer a ByteArray as the response.

Then, to start the server:

	myServerSocket _ MaServerSocket new
		listenOn: 12345
		answer:
			[ :requestByteArray |
			... give requestByteArray to your server program ... ]

MaServerSocket utilizes SharedQueue's and background Processes to ensure that request processing is not held up by sending or receiving the ByteArray's over the network, which occurs entirely in the background. The answer block is only ever evaluated for one client request at a time.

When you're done, be sure to shutdown the socket so resources are properly deallocated:

	myServerSocket shutdown

Getting answers in the client

Your client program creates a MaClientSocket by specifying the ip address as numbers in a ByteArray:

	mySocket _ MaClientSocket hostAddress: #(192 168 1 1) asByteArray port: 12345.

No connections are made just from creating the socket. That happens when you actually send the request:

	responseByteArray _ mySocket sendData: myRequestByteArray

There's also a sendData:startingAt:count:waitForReplyIn: method for maximum efficiency. If the reply ByteArray you supply wasn't large enough, you'll get a bigger one.

Optional Socket Events

The MaServerSocket knows about a "server", which defaults to a MaServer that does nothing. But if you subclass MaServer and override some of its methods they'll be called when a socket is queued, a ByteArray request has been fully delivered, or sending a response, etc. See MaServer for more information.

Using the Object Request Layer

If you choose to use the object request layer, you send "request" objects and get back arbitrary response objects. So you write your client and server programs the same except you don't concern yourself with parsing ByteArrays anymore.

Setting up the server

When you are ready to start your server program, instead of creating a MaServerSocket, you create a MaTcpRequestServer:

	myServer _ MaTcpRequestServer protocol:
		{ MyRequestClass1. 
		MyRequestClass2.  
		MyResponseClass1.  
		MyResponseClass2.
		OrderedCollection.
		Dictionary. "etc." }.

What's this? Yes, you have to tell it all the classes that you'll be sending and receiving, accounting for the full object-graph of your requests. For example, if you have SubmitArticleRequest that has an Article object, you must include not only SubmitArticleRequest, Article and all the other kinds of objects that Article references, and what they reference, and so on. You don't however, need to ever specify String, ByteArray, Set, Symbol, Array, SmallInteger, Float, True, False, or UndefinedObject. Those are automatically part of every protocol.

You may also optionally specify a MaServerConsole to receive events. Subclass MaServerConsole and override one of its notification methods and it'll be called if you:

	myServer _ console: myConsole

When you're ready to start the server, you use processOn:do:

	myServer
		processOn: 12345 ;
		using:
			[ :requestObject |
			... pass requestObject to your server program, which answers the response ... ]

When you're done, you need to shutdown to release operating system resources:

	myServer shutdown

Setting up the client

Your client program creates a MaTcpRequestServerLink pointing to the server hostAddress and port is is listening:

	myLinkToServer _ MaTcpRequestServerLink
		hostAddress: #(192 168 1 1) asByteArray
		port: 12345

Before you can do anything, you have to connect. This will ensure you have all the needed protocol in this client image (and throw an exception if you don't).

	myLinkToServer connect

To balance network fluctuations against your patience, you may wish to override the default timeout period from 30 seconds:

	myLinkToServer timeoutSeconds: 30

Getting answers in the client

Now that you're connected, your client program can get answers from the server by:

	myLinkToServer submit: someRequestObject

Remember, someRequestObject will be a member of the protocol, as will the response you get back from calling submit:.

That's it! When you're done, don't forget to disconnect so as you release network resources back to the operating system.

	myLinkToServer disconnect

Ma client server-cmm.mcz.sar