Examples

TcpIp using the same port

In the previous example we had one cell connecting to another remote cell using an ip address and a port number. In this example we show how the same address and port number can be used to set up many communications to the remote system.

Note that when the communication with a remote system is set up, you simply use the cell references you get from the remote system to send messages to cells, in just the same way as you do for a local system. You do not need to set up a communication for each cell you want to communicate with. You can for example ask the remote system the cell reference for this or that service and then simply use the cell reference to send messages to. But before you can have any idea which system you are talking to, you have to set up the connection. In later examples we will see that a connection can be used also for different protocols then the CellSpeak protocol which is used to cummunicate between systems running a CellSpeak VM.

When a CellSpeak connection is established between two systems, a special cell is created automatically at each side of the communication: the avatar. Whenever you send a message to a cell on the remote system, it actually goes to the message queue of the avatar. The avatar will then do the actual sending of the message using the protocol that was agreed between the two systems. The fact that there is an avatar is fully transparent to the application.

Messages that are received over a connection do not transit via the avatar, but are delivered directly to the message queue of the destination cells.

Apart from the avatar, which packages and sends messages, you also might want to have a cell that handles the comms channel for example to initiate some special action when the communication is lost. For this purpose you can specify your own 'handler' cell.






(1) In this case we do all the connections at the same place - in reality an application could very well connect to a remote system in several places.


(2) The Conx parameter is a reference to the connection used for the comms between the two systems. We need it here to set the protocol for the communication between the two systems - we do not need to store it.

(3) A connection determined by an ip-address and port number, can only handle one protocol. If the protocol would already have been set to a different type, then the Humanoid would get an error message.






(4) The avatar stands for the cell that is listening on the other side of the connection.




(5) When a reply comes back, it will not come from the avatar, but from the cell on the other system.

12 TcpIp using the same port.celsrc
-.-
Connecting with several cells on a remote system using the same port number.

In this example we use the same message exchange as in the previous example, 
but now we let many cells communicate with each other over the same port number.	
-.-------------------------------------------------------------------------------------------------
use Windows, Math, Strings, Editor, System

-- The connection test creates a Talker and a Listener and have them exchange some messages
design ConxTest is

	cell Caller, Callee
	cell Creator
	cell stdout

	constructor is 
		-- Create a window for output
		stdout = create MenuWindow("Connecting to a remote CellSpeak system over Tcp/Ip")
		
		-- send a message to the system to set stdout		
		system <- stdout.Set(stdout)
			
		-- Create the Talker that will connect to a port on a remote system..
		create TalkerDesign("Apollo","27524")
		
		-- There is one listener on port 27524 ..
		create ListenerDesign("27524")
	end
end

--	The Talker connects several times to the remote system using the same address
design TalkerDesign( ansi Remote, ansi Port) is 

	cell ConxMgr			-- The reference to the connection manager
	keep Remote, Port		-- we keep the parameters

	constructor is 	
		-- Ask the system for the Connection Manager
		system <- Service.Get("ConxMgr")
	end
	
	on Service.Provider(ansi Service, cell Provider) do	
		-- check the service
		Service is "ConxMgr" ? ConxMgr = Provider : yield

		-- Let's set up a number of connections using the same port number
(1)		for i=1 to 5 => ConxMgr <- TCPIP.Connect(Remote, Port)			
	end
	
	-- The connection mgr sends this message if the connection was successfuly established
	var Count = 0	-- a variable to tally the nr of connections
(2)	on TCPIP.Connected( ConxClass Conx ) do	
		-- create a new humanoid - this cell will handle the connection
		cell Humanoid = create HumanoidDesign("Humanoid[Count+=1]")
	
		-- set the protocol to be used over the connection.
(3)		ConxMgr <- Set.Protocol( Conx, "CLSPK", Humanoid )
	
		-- print a message on the display
		system <- println("\tconnection to [Remote] port [Port] established.")		
	end
	
end

--	The Humanoid handles the communications on the connection
design HumanoidDesign(ansi Name) is
	keep Name
	cell Avatar, ConxMgr
	
	-- The response of the connnection mgr to the Set.Protocol message
(4)	on CLSPK.Ready( cell Avatar ) do	
		keep Avatar				-- The avatar is the local representative of the remote system
		ConxMgr = sender		-- We received the message from the connection manager
		
		-- inform
		system <- println("[Name]: contacting other system")
		
		-- send a welcome messageto the remote system
(5)		Avatar <- HelloThere(Name)
	end
	
	-- The connection manager sends this message when the connection is disconnected
	on TCPIP.RemoteDisconnected( ConxClass Conx) do
		system <- println("[Name] Remote Disconnected")
	end
	
	-- The response from the callee on the remote system
	on MyNameIs(ansi NameCallee) do
		system <- println("[Name]: my counterpart's name is [NameCallee]")
		
		-- send a nr of messages to my counterpart
		for i=1 to 5000 => sender <- TestMessage("Message [i]:0123456789 abcdefghijklmnopqrstuvwxyz")
		
		-- and ask how many received
		sender <- HowManyReceived
	end
	
	-- The Callee reports the nr of messages received
	on Received(int count, ansi CalleeName) do
		system <- println("[Name]: [CalleeName] received a total of [count] messages")
		
		-- Tell our counterpart we're finished
		sender <- DemoIsOver	

		-- and we autodestroy
		destroy self
	end
	
	-- The destructor for the cell
	destructor is 
		system <- println("[Name] going down")
	
		-- We close the connection (the avatar is destroyed automatically)
		ConxMgr <- TCPIP.Close( Avatar )
	end 
end

--	The listener listens to incoming calls on a port and launches a handler for each incoming connection request
design ListenerDesign(ansi Port) is 
	cell ConxMgr			-- The reference to the connection manager
	keep Port				-- We keep the port number
	
	constructor is 
		-- The callee also needs the connection manager
		system <- Service.Get("ConxMgr")	
	end

	destructor is 
		-- stop listening
		ConxMgr <- TCPIP.Stop.Listening(Port)				
	end

	-- The reply from the system on our request for a service
	on Service.Provider(ansi Service, cell Provider) do
		-- check that we have received the right service - otherwise yield
		Service is "ConxMgr" ? ConxMgr = Provider : yield
		
		-- We tell the connection manager that we want to listen for incoming connections on a port
		ConxMgr <- TCPIP.Listen( Port )
	end
	
	int Count = 0			-- we keep track of the nr of connections
	
	-- The message we get from the connection manager when a remote system wants to connect
	on TCPIP.Accept( ConxClass Conx ) do		
		system <- println("\taccepting connection [Conx].")
		
		-- For each accepted connection we create a new handler
		var NewRobot = create RobotDesign("Robot[Count+=1]")
				
		-- Set the protocol and the handler
		ConxMgr <- Set.Protocol( Conx, "CLSPK", NewRobot)
	end 	
end

--	The robot handles messages on an accepted connection
design RobotDesign(ansi Name) is 

	keep Name
	cell Avatar, ConxMgr
		
	-- The conx mgr informs us about success (or failure) of the Set.Protocol message
	on CLSPK.Ready(cell Avatar) do	
		keep Avatar				-- keep a reference to the avatar..
		ConxMgr = sender		-- ..and the connection manager
		
		system <- println("\tReceived avatar")
	end
	
	-- The connection manager sends this when the remote system disconnects
	on TCPIP.RemoteDisconnected( ConxClass Conx) do	
		system <- println("[Name] Remote has closed the connection")	
	end
	
	-- The connection manager sends this when a protocol is not supported (CLSPK is supported of course !)
	on CLSPK.NotSupported  do
		system <- println("CLSPK is not supported")		
	end
	
	-- The message from our counterpart on the other system
	on HelloThere(ansi RemoteName) do
		system <- println("[Name]: [RemoteName] says hello to me")
		
		-- our reply
		sender <- MyNameIs(Name)
	end
		
	-- The caller will send a series of test messages ..
	int ReceiveCount = 0	
	
	on TestMessage(byte[] Content) do
		-- just count the nr of messages
		ReceiveCount += 1
	end
	
	-- ..and ask how many were received
	on HowManyReceived do 
		-- return the message count
		sender <- Received(ReceiveCount, Name)
	end
	
	on DemoIsOver do
		-- when the demo is over we autodestruct
		destroy self
	end
	
	-- The destructor of the robot
	destructor is 
		system <- println("\t[Name] going down")

		-- ..and we close the connection
		ConxMgr <- TCPIP.Close( Avatar )
	end
end