System: client_and_server

Created on: Sun Sep 13 22:03:17 2015


This system has been defined in USL; and automatically analyzed and automatically generatated/resource allocated (RAT)ed to C code using the 001 Toolsuite.

The client/server system uses the OMap Editor to ask the user for input (System Inputs) and responds with the results (System Outputs). In this client/server example, the user enters two books (book1 and book2).

The server then counts the total number of occurrences of words in the two documents. To do this the server calls the function ngram_test which is an FMap in another library that implements a MapReduce like algorithm (not shown in detail).

The Map Phase of MapReduce makes a set of key-value pairs following a 1-ngram approach. This means that each word becomes a key with the value of “1”. The set is really a bag of word-value pairs in which each word as a key may be duplicated; but each word as a key will have the value “1”.

The Reduce Phase will collect each of the duplicated keys into a unique keyed (word) set of values (or counts). The counts are collected for all the unique keyed set elements (i.e., words). Then, for each unique keyed word, the set of counts are summed to get the total number of counts for each keyed word. This set of unique keyed value pairs, as word-count pairs, is converted to a set of msgs(OSetof)msg(str) in the format: word:count.



1 client_and_server.

Interface: msgs:msgs=client_and_server(msgs0:msgs,os:os)


1.1 client.

client starts a server on the same host as the client, waits for two seconds and then requests the server to make a two-way communication channel for sending and receiving data. In our example, the variables hearFrom and talkTo are the CPort (connected port) ends for communication between the client and server:

client:talkTo --> Server

client:hearFrom <-- Server

Interface: ms:msgs=client(ms0:msgs,os0:os)


1.1.1 ssh_exec.

ssh_exec merges together the ssh command, the user and host name and the path/executable, pathexe. This command, cmd, is then executed using the spawnNoWait function to start the server either locally or on a foreign machine designated for hosting the server.

Interface: os:os=ssh_exec(os0:os,user:str,host:str,pathexe:str)

(ssh_exec.c) merge_5_strs.

merge_5_strs merges the Strs 1, 2, 3, 4 and 5 in order at the end of s0 resulting in s.

Interface: s:str=merge_5_strs(s0:str,1:str,2:str,3:str,4:str,5:str)


1.1.2 connect_to_server.

connect_to_server makes a host INet address, encoded as a binary integer, and adds the port "5000" to it to get the server's INet address and listening port. Then the client issues a requestConnext:CPort function to initiate the server's listening port to request a communication channel for talking to the server.

Interface: talkToServer:Cport=connect_to_server(host:str,os:os)


1.1.3 send_msgs.

send_msgs sets up a synchronous SELECT system call to talk to the server with the client's end of communication channel set up by the server (and accessed by the client with requestConnect:CPort). If the client is notified (through SELECT) that it is ok to talk, the client sends its messages, ms0, to the server by converting those messages to an OMap form and then to a STR string form to marshall the data to the server (who is synchronously waiting for them).

Interface: hearFrom:Cport=SEND_MSGS(ms0:msgs,talkTo:Cport,FOREVER:nat)

(send_msgs.c) write_error_select.

write_error_select sets up the client for writing to the cport0 CPort channel provided by the server. To do this, the cport0 descripter is added to the file descriper sets for error and write (using the add:CPORT,fdset functions). The SELECT:fdset function will return when either of the write or error fdsets are signaled via the cport0 descripter. The form for the SELECT primitive operation is:

Nat:matches,FDset:read,FDset:write,FDset:error=SELECT:FDset(FDset:read,FDs et:write,FDset:error,Nat:timevalue)

write_error_select then checks to see if cport0 is in the descripter sets, e or w, using the operation is_present_in_fdset.

Interface: wb:boolean,eb:boolean,nb:boolean=write_error_select(cport0:Cport,timeval:n at)

(write_error_select.c) is_present_in_fdset.

is_present_in_fdset checks to see if the CPort, cport, is in the descripter set, fdset. If it is present, a TRUE value is returned for the Boolean, b0; otherwise a FALSE or REJECT value is returned. Here, if b0 is REJECT, we set the value of b to be FALSE.

Interface: b:boolean=is_present_in_fdset(cport:Cport,fdset:FDSet)

(is_present_in_fdset.c) id_d3.

id_d3 selects a0 to become a and the objects 1, 2 and 3 are deallocated.

Interface: a:Any=id_d3(a0:Any,1:Any,2:Any,3:Any)

() sendOMap.

sendomap is a universal (polymorphic) operation that takes as a parameter, OSETOFTYPE. Given the particular OSETOFTYPE for set, set will be converted from its strongly typed OSETOFTYPE viewpoint to its weakly typed OMap object viewpoint, om. The om OMap set object is further transformed to a Str string, omstr0. The size of the omstr0 object is determined; the size converted to a string; and then prefixed to the omstr0 object. At this point, we have a string, omstr, with the format:


This string object will be marshalled (sent) to the other end of the CPort communication channel, cport0, by the function, Send_a_str_CPort.

Interface: cp:Cport=sendOMap(cport0:Cport,set:Any)


1.1.4 receive_msgs.

receive_msgs sets up a SELECT system call using the function read_error_select. In our current case, the wait Nat value is REJECT indicating the our recieve process is to be synchronous. If the value of the Boolean, r, is "TRUE" for reading, then the CAN_RECEIVE sub-function is performed. An OMap string is received from the CPort, cp0, by function Receive_a_Str_CPort (through data marshalling and used by either the client or server from either end of their communication channel). Once the OMap data STR string is received, it is converted to a msgs (OSetOf) object containing the transmitted information.

Interface: ms:msgs=RECEIVE_msgs(cp0:Cport,wait:nat)


1.2 server.

server starts on the host designated by the client (in our example, on the same host as the client) and creates a listening port/INet address. It then sets up the SELECT system call for listening--waiting for a client. When a client issues RequestConnect:CPort on the port/INet address (see connect_to_server called from client) the SELECT function returns. If all goes well, the server connects to the client using the awaitconnect:lport function (see connect_to_client) and attempts to handle the clients request. The server synchronously receives the clients msgs because FOREVER is set to the REJECT Nat value. The msgs, ms, are sent to the function to handle the client's request; here, ngram_test. Once the requested function returns, the server sends the resulting msgs, sums, back to the client by converting the sums msgs to an OMap and then marshalling the OMap as a STR string object to the client. After this is done, the server exits.

Interface: os:os=server(os00:os)


1.2.1 debug_server.

Interface: b:boolean=DEBUG_SERVER(path:str,name:str,os:os)

(debug_server.c ) append_3_strs.

append_3_strs appends, in order, the strings 1, 2 and 3 to the end of the string s0 resulting in a new string s.

Interface: s:str=append_3_strs(s0:str,1:str,2:str,3:str)


1.2.2 setup_listening_INet_port.

setup_listening_inet_port sets up the servers INet address and port for listening for a client. The server which is running now in a user account on a host machine, gets its host machine hostname, makes a binary Integer INet address from it (host), and adds the listening port to the address, "5000". A "1000" byte buffer for messages arriving on the listening port is set.

Interface: listenOn:Lport=setup_listening_INet_port(os0:os)

( setup_listening_inet_port.c)

1.2.3 set_SELECT_for_listening.

set_select_for_listening sets the listening LPort, listenOn, to wait (FOREVER) for any client that knows its INet/port address. After setting up the descripter sets read and error to be signaled when listenOn is activated, the time_SELECT_on_fdsets function is used to perform listening (synchronously listening in our case because of the k:REJECT,nat function, see select:fdset in the operation read_error_select for details).

Interface: fdss3:fdsets,n:nat=set_SELECT_for_listening(listenOn:Lport)

( set_select_for_listening.c) create_fdsets.

create_fdsets creates a TupleOf object of type fdsets for setting up the SELECT system call file descripter sets (fdsets), fds.

Interface: fds:fdsets=create_fdsets(anyNAT:nat)

( create_fdsets.c) kput.

kput creates a new child of p0 and then puts it into p0 resulting in p.

Interface: p:Any=kput(p0:Any)

() add_to_fdsets.

add_to_fdsets is a universal operation that adds a particular PORT type to an fdsets CHILD node of an fdsets TupleOf object.

Interface: fdss:fdsets=add_to_fdsets(port:Any,fdss0:fdsets)

() time_select_on_fdsets.

time_select_on_fdsets gets the descripter setups from fdset, fdss0, for reading, writing and exception (error), calls the SELECT system call and puts the response back into fdset, fdss.

Interface: fdss:fdsets,n:nat=time_select_on_fdsets(fdss0:fdsets,timeval:nat)

(time_select_on_fdsets.c )

1.2.4 viewmore_2.

viewmore_2 provides access to the two children objects, 1 and 2, contained in the object t.

Interface: 1:Any,2:Any=viewmore_2(t:Any)


1.2.5 connect_to_client.

connect_to_client waits (using the primitive function, awaitconnect:lport) for a client to connect to its INet address listening port. When there is a client on the listening port, client0 is returned as the server's end to a communication port for talking and passing data to a client.

Interface: client:Cport=connect_to_client(listenOn:Lport,fdss:fdsets)

(connect_to_client.c) id_d1.

id_d1 selects a0 to become a and the object 1 is deallocated.

Interface: a:Any=id_d1(a0:Any,1:Any)


1.2.6 ngram_test.

ngram_test loads a set of files (simulating the MapReduce SPLIT function) from a server directory, dir. It makes a set of name/value pairs (i.e., word:"1") for each word found in the set of documents. It then executes a REDUCE-PHASE reader function, grouping of same named keys function (collecting associated value counts into a counts set) and summing the values for each unique key (i.e., word). Finally, ngram_test converts the summed set of key/values into a msgs set to present to the user.

Interface: sumMsgs:msgs=ngram_test(fileNms0:msgs)



1 client_and_server

1.1 client


1.1.1 ssh_exec

ssh_exec.c merge_5_strs


1.1.2 connect_to_server


1.1.3 send_msgs

send_msgs.c write_error_select

write_error_select.c is_present_in_fdset

is_present_in_fdset.c id_d3 sendOMap

1.1.4 receive_msgs


1.2 server


1.2.1 debug_server

debug_server.c append_3_strs


1.2.2 setup_listening_INet_port


1.2.3 set_SELECT_for_listening

set_select_for_listening.c create_fdsets

create_fdsets.c kput add_to_fdsets time_select_on_fdsets


1.2.4 viewmore_2

1.2.5 connect_to_client

connect_to_client.c id_d1

1.2.6 ngram_test