STORE_MANAGER is invoked first from the command line on a computer. It creates a datagram socket and binds it to a port chosen by the system. It then writes on the screen the port number associated with its socket. The client processes RAND_PROC1 and RAND_PROC2 are invoked after STORE_MANAGER displays the port number assigned to its socket. Each client process is invoked from the command line with arguments specifying the host name of the computer that STORE_MANAGER is running on, the port number displayed by STORE_MANAGER, the logical identifier for the client process and the seed for the random number generator. Each client process may be invoked on the host running STORE_MANAGER or on a different computer. RAND_PROC1 and RAND_PROC2 execute identical algorithms but use different seeds for the random number generator.
Given this set up, the program may be organized into two files - store_manager.c and rand_proc.c (additional header files may be used to group together data structures and operations needed in each process). Thus STORE_MANAGER may be run, say on snowhite server, by invoking
store_manager
at the command line at snowhite server. Thereafter RAND_PROC1 may be run, say on astro, by invoking
rand_proc hostname portnumber identifier seed
at the command line on astro, where
are the arguments to the program in rand_proc.c. Likewise RAND_PROC2 may be run on snowhite, astro, or any other machine of your choice by invoking rand_proc as shown above with the appropriate arguments from the command line on that computer. The files store_manager and rand_proc contain the executable code for store_manager.c and rand_proc.c respectively.hostname : host name of the computer that STORE_MANAGER is running on, in this example, snowhite.cis.temple.edu, portnumber : the port number displayed on the screen by STORE_MANAGER, identifier : the logical identifier for the client process, 1 for RAND_PROC1, and 2 for RAND_PROC2, and seed : seed for the random number generator
Since STORE is maintained by STORE_MANAGER and RAND_PROC1 and RAND_PROC2 are not supposed to access it directly, these declarations should be local to STORE_MANAGER.const STRING_LENGTH = 20; SSTORE_SIZE = 10; type STRING_TYPE = array [0..STRING_LENGTH - 1] of char; SSTORE_ENTRY_TYPE = record SSTORE_ID : STRING_TYPE; SSTORE_ELEM : STRING_TYPE; end; SSTORE_TYPE = array [0..SSTORE_SIZE - 1] of SSTORE_ENTRY_TYPE; var STORE : SSTORE_TYPE;
Read and update operations requested by RAND_PROC1 and RAND_PROC2 specify a value for the SSTORE_ID component (through the parameter WHO in the functions SSTORE_READ() and SSTORE_UPDATE()). If an entry with that value for the SSTORE_ID component is found in STORE, the operation is performed on the entry, otherwise a response indicating failure is generated. RAND_PROC1 and RAND_PROC2 select values for the parameter WHO randomly from a list maintained in each process. This list contains ALL values held in the SSTORE_ID components in STORE, and also an additional value that is not present in STORE. Thus the list contains SSTORE_SIZE + 1 values, and the value not contained in STORE is selected, on the average, once every (SSTORE_SIZE + 1) trials, causing the operations requested by the process to fail at the above rate.
Update operations specify (through the parameter WHAT) a value to be assigned to the SSTORE_ELEM component of a specified entry in STORE, obliterating the value currently held in it. We will stipulate that RAND_PROC1 would ALWAYS use a string of 1's (of length STRING_LENGTH) and RAND_PROC2, a string of 2's (also of length STRING_LENGTH), for the parameter WHAT when requesting an update operation. Recall that the SSTORE_ELEM component of each element of STORE is initialized with a string of 0's by STORE_MANAGER. Thus the SSTORE_ELEM component of an entry in STORE can hold one of three values :
STORE_MANAGER first creates an Internet domain datagram socket. It then binds a local address to the socket, getting the system to pick a port number for it. It queries the system for the port number assigned to the socket and writes the port number on the screen. Recall that the host name of the computer that STORE_MANAGER is invoked on and the port number displayed by STORE_MANAGER are made available to RAND_PROC1 and RAND_PROC2 through command line arguments. This enables them to construct the address associated with the socket created by STORE_MANAGER. The following is an outline of the steps carried out by STORE_MANAGER in establishing a socket.
Algorithm SetUpSocketInStoreManager
begin
1. Create a datagram socket by invoking socket() as
s := socket(AF_INET,SOCK_DGRAM,0);
2. Bind local address to socket as follows :
{ sm_socket_address is assumed to be declared as a variable of type
struct sockaddr_in }
sm_socket_address.sin_family := AF_INET;
sm_socket_address.sin_addr.s_addr := INADDR_ANY;
{ The wildcard INADDR_ANY matches all valid network addresses of
the computer. }
sm_socket_address.sin_port := 0; { Let system pick port number }
Now invoke bind() as
bind(s,&sm_socket_address,sizeof(sm_socket_address));
3. Find the port number assigned by the system by invoking
getsockname() as
getsockname(s,&sm_socket_address,&length_of_address);
4. Print the host's representation of the port number,
ntohs(sm_socket_address.sin_port;
end SetUpSocketInStoreManager
Each client process also creates a datagram socket and binds an
address to it, having the system select a port number for the socket.
STORE_MANAGER gets the address of the socket in a client when
it receives a message (containing a request for a read or update
operation) from the client, and sends its response to the socket
associated with that address. The client process constructs the
address of the socket in STORE_MANAGER from the host name and the port
number arguments, and sends its messages requesting read and update
operations to this address. Algorithm SetUpSocketInRandProc
details the steps outlined above.
Algorithm SetUpSocketInRandProc begin 1. Create a datagram socket by invoking socket() as s := socket(AF_INET,SOCK_DGRAM,0); 2. Bind local address to socket as follows : { rp_socket_address is assumed to be declared as a variable of type struct sockaddr_in } rp_socket_address.sin_family := AF_INET; rp_socket_address.sin_addr.s_addr := INADDR_ANY; { The wildcard INADDR_ANY matches all valid network addresses of the computer. } rp_socket_address.sin_port := 0; { Let system pick port number } Now invoke bind() as bind(s,&rp_socket_address,sizeof(socket_address)); 4. Construct the address of the socket created by STORE_MANAGER by assigning the appropriate values to the components of sm_socket_address. sm_socket_address is assumed to be declared as a variable of type struct sockaddr_in. sm_socket_address.sin_family := AF_INET; Get the IP address of the computer running STORE_MANAGER from the the first command line argument : { assumes the declaration struct hostent *host_info; } host_info := gethostbyname(argv[1]); Assign the IP address by copying individual bytes, invoking bcopy as bcopy(host_info->h_addr,&sm_socket_address.sin_addr, host_info->h_length); Assign the network representation of the port number from the second command line argument : sm_socket_address.sin_port := htons(atoi(argv[2])); { Now sm_socket_address contains the address of the socket created by STORE_MANAGER. } end SetUpSocketInRandProc
Following this scheme, RAND_PROC1 and RAND_PROC2 invoke the function sendto() to send a message to STORE_MANAGER, and STORE_MANAGER invokes recvfrom() to receive messages from the clients. The function recvfrom() returns to STORE_MANAGER the address of the socket associated with the sender (through one of its parameters) and STORE_MANAGER sends its response to the request specifying this address for the destination. The functions sendto() and recvfrom() may be used in the transmission of messages from STORE_MANAGER to the clients as well.
The details of sending and receiving messages should be hidden in the functions SSTORE_READ() and SSTORE_UPDATE() invoked by the client processes. The intent is to avoid burdening the user with the details of the implementation and present an interface that specifies only the semantics of the operation.
The above discussion applies to messages originating from STORE_MANAGER as well. Response messages for all cases except that of an invalid read operation have the same length, but the latter requires fewer characters. All cases may, however, be handled in a uniform manner by getting STORE_MANAGER to put in some padding in the messages containing the response to invalid read operations.
Entries in the file store.log maintained by STORE_MANAGER summarize requests from the clients and the corresponding responses from STORE_MANAGER. Each entry recording a request identifies the client making the request (RAND_PROC1 or RAND_PROC2), the operation requested (read or update), the parameters of the operation, and a timestamp. Each entry recording the response to a request indicates the operation requested, the parameters of the operation, the status returned for the operation, and a timestamp. Each entry in the file may be written on a separate line for clarity.
The following are examples of the suggested format :
1 R jedi.cis.temple.edu < timestamp >
R jedi.cis.temple.edu 00000000000000000000 OK < timestamp >
2 U jedi.cis.temple.edu 22222222222222222222 < timestamp >
U jedi.cis.temple.edu 22222222222222222222 OK < timestamp >
2 U yoda.cis.temple.edu 22222222222222222222 < timestamp >
U yoda.cis.temple.edu 22222222222222222222 OK < timestamp >
1 R yoda.cis.temple.edu < timestamp >
R yoda.cis.temple.edu 22222222222222222222 OK < timestamp >
1 U none.cis.temple.edu 11111111111111111111 < timestamp >
U none.cis.temple.edu 11111111111111111111 ERR < timestamp >
2 R none.cis.temple.edu < timestamp >
R none.cis.temple.edu -------------------- ERR < timestamp >
The last two operations fail because "none.cis.temple.edu" is not
a valid SSTORE_ID value in STORE.
The client processes RAND_PROC1 and RAND_PROC2 log the messages they send and receive to the files rand_proc1.xxx and rand_proc2.xxx respectively, where the extension in the file name is the name of the computer the client is run on. The name of the machine that the client is invoked on may be passed as the fifth argument to the client process to generate the appropriate name for its log file. Entries in the files correspond to the requests sent and the responses received by the respective processes. Each entry recording a request identifies the operation requested (read or update), the parameters of the operation, and a timestamp. Each entry recording a response indicates the operation requested, the parameters of the operation, the status returned for the operation by STORE_MANAGER, and a timestamp. Each entry may be written on a separate line for clarity. The log generated by RAND_PROC1 corresponding to the sequence of requests from the example log of STORE_MANAGER shown above :
The log generated by RAND_PROC2 corresponding to the sequence of requests from the example log of STORE_MANAGER shown above :R jedi.cis.temple.edu < timestamp > R jedi.cis.temple.edu 00000000000000000000 OK < timestamp > R yoda.cis.temple.edu < timestamp > R yoda.cis.temple.edu 22222222222222222222 OK < timestamp > U none.cis.temple.edu 11111111111111111111 < timestamp > U none.cis.temple.edu 11111111111111111111 ERR < timestamp >
U jedi.cis.temple.edu 22222222222222222222 < timestamp > U jedi.cis.temple.edu 22222222222222222222 OK < timestamp > U yoda.cis.temple.edu 22222222222222222222 < timestamp > U yoda.cis.temple.edu 22222222222222222222 OK < timestamp > R none.cis.temple.edu < timestamp > R none.cis.temple.edu -------------------- ERR < timestamp >