rpc_lesson1

Two models run in a client-server, remote procedure call (RPC) communication pattern. The client model client sends requests and receives response to/from the server model server via the deprecated call method. The server model receives requests and send responses. This example demostrates the RPC pattern through the use of the client_of and is_server model parameters and the RPC interface classes/functions. The client model also sends request/response pairs to a file.

C Version

Model Code:

 1#include "YggInterface.h"
 2#include <stdio.h>
 3
 4
 5int get_fibonacci(int n) {
 6  int pprev = 0, prev = 1, result = 1, fib_no = 1;
 7  while (fib_no < n) {
 8    result = prev + pprev;
 9    pprev = prev;
10    prev = result;
11    fib_no = fib_no + 1;
12  }
13  return result;
14};
15
16
17int main(int argc, char *argv[]) {
18  
19  int exit_code = 0;
20  printf("Hello from C server!\n");
21
22  // Create server-side rpc conneciton using model name
23  yggRpc_t rpc = yggRpcServer("server", "%d", "%d");
24
25  // Continue receiving requests until the connection is closed when all
26  // clients have disconnected.
27  int flag, n, result;
28  while (1) {
29    printf("server(C): receiving...\n");
30    flag = rpcRecv(rpc, &n);
31    if (flag < 0) {
32      printf("server(C): end of input\n");
33      break;
34    }
35
36    // Compute fibonacci number
37    printf("server(C): Received request for Fibonacci number %d\n", n);
38    result = get_fibonacci(n);
39    printf("server(C): Sending response for Fibonacci number %d: %d\n",
40	   n, result);
41
42    // Send response back
43    flag = rpcSend(rpc, result);
44    if (flag < 0) {
45      printf("server(C): ERROR sending\n");
46      exit_code = -1;
47      break;
48    }
49  }
50
51  printf("Goodbye from C server\n");
52  return exit_code;
53};
 1#include "YggInterface.h"
 2#include <stdio.h>
 3
 4
 5int main(int argc, char *argv[]) {
 6   
 7  int iterations = atoi(argv[1]);
 8  int exit_code = 0;
 9  printf("Hello from C client: iterations %d\n", iterations);
10  
11  // Set up connections matching yaml
12  // RPC client-side connection will be $(server_name)_$(client_name)
13  yggRpc_t rpc = yggRpcClient("server_client", "%d", "%d");
14  yggOutput_t log = yggOutputFmt("output_log", "fib(%-2d) = %-2d\n");
15
16  // Initialize variables
17  int ret = 0;
18  int fib = -1;
19  char *logmsg = (char*)malloc(YGG_MSG_MAX*sizeof(char));
20  int i;
21
22  // Iterate over Fibonacci sequence
23  for (i = 1; i <= iterations; i++) {
24    
25    // Call the server and receive response
26    printf("client(C): Calling fib(%d)\n", i);
27    ret = rpcCall(rpc, i, &fib);
28    if (ret < 0) {
29      printf("client(C): RPC CALL ERROR\n");
30      exit_code = -1;
31      break;
32    }
33    printf("client(C): Response fib(%d) = %d\n", i, fib);
34
35    // Log result by sending it to the log connection
36    ret = yggSend(log, i, fib);
37    if (ret < 0) {
38      printf("client(C): SEND ERROR\n");
39      exit_code = -1;
40      break;
41    }
42  }
43
44  free(logmsg);
45  printf("Goodbye from C client\n");
46  return exit_code;
47    
48}
49

Model YAML:

1---
2
3model:
4  name: server
5  language: c
6  args: ./src/server.c
7  is_server: True  # Creates a RPC server queue called "server"
 1---
 2
 3model:
 4  name: client
 5  language: c
 6  args:
 7    - ./src/client.c
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True

C++ Version

Model Code:

 1#include "YggInterface.hpp"
 2#include <stdio.h>
 3
 4
 5int get_fibonacci(int n) {
 6  int pprev = 0, prev = 1, result = 1, fib_no = 1;
 7  while (fib_no < n) {
 8    result = prev + pprev;
 9    pprev = prev;
10    prev = result;
11    fib_no = fib_no + 1;
12  }
13  return result;
14};
15
16
17int main(int argc, char *argv[]) {
18  
19  int exit_code = 0;
20  printf("Hello from C++ server!\n");
21
22  // Create server-side rpc conneciton using model name
23  YggRpcServer rpc("server", "%d", "%d");
24
25  // Continue receiving requests until the connection is closed when all
26  // clients have disconnected.
27  int flag, n, result;
28  while (1) {
29    printf("server(C++): receiving...\n");
30    flag = rpc.recv(1, &n);
31    if (flag < 0) {
32      printf("server(C++): end of input\n");
33      break;
34    }
35
36    // Compute fibonacci number
37    printf("server(C++): Received request for Fibonacci number %d\n", n);
38    result = get_fibonacci(n);
39    printf("server(C++): Sending response for Fibonacci number %d: %d\n",
40	   n, result);
41
42    // Send response back
43    flag = rpc.send(1, result);
44    if (flag < 0) {
45      printf("server(C++): ERROR sending\n");
46      exit_code = -1;
47      break;
48    }
49  }
50
51  printf("Goodbye from C++ server\n");
52  return exit_code;
53};
 1#include "YggInterface.hpp"
 2#include <stdio.h>
 3
 4
 5int main(int argc, char *argv[]) {
 6   
 7  int iterations = atoi(argv[1]);
 8  int exit_code = 0;
 9  printf("Hello from C++ client: iterations %d\n", iterations);
10  
11  // Set up connections matching yaml
12  // RPC client-side connection will be $(server_name)_$(client_name)
13  YggRpcClient rpc("server_client", "%d", "%d");
14  YggOutput log("output_log", "fib(%-2d) = %-2d\n");
15  
16  // Initialize variables
17  int ret = 0;
18  int fib = -1;
19  char *logmsg = (char*)malloc(YGG_MSG_MAX*sizeof(char));
20  int i;
21
22  // Iterate over Fibonacci sequence
23  for (i = 1; i <= iterations; i++) {
24    
25    // Call the server and receive response
26    printf("client(C++): Calling fib(%d)\n", i);
27    ret = rpc.call(2, i, &fib);
28    if (ret < 0) {
29      printf("client(C++): RPC CALL ERROR\n");
30      exit_code = -1;
31      break;
32    }
33    printf("client(C++): Response fib(%d) = %d\n", i, fib);
34
35    // Log result by sending it to the log connection
36    ret = log.send(2, i, fib);
37    if (ret < 0) {
38      printf("client(C++): SEND ERROR\n");
39      exit_code = -1;
40      break;
41    }
42  }
43
44  free(logmsg);
45  printf("Goodbye from C++ client\n");
46  return exit_code;
47}

Model YAML:

1---
2
3model:
4  name: server
5  language: c++
6  args: ./src/server.cpp
7  is_server: True  # Creates a RPC server queue called "server"
 1---
 2
 3model:
 4  name: client
 5  language: c++
 6  args:
 7    - ./src/client.cpp
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True

Fortran Version

Model Code:

 1program main
 2  use fygg
 3
 4  interface
 5     function get_fibonacci(n) result(out)
 6       integer, intent(in) :: n
 7       integer :: out
 8     end function get_fibonacci
 9  end interface
10
11  type(yggcomm) :: rpc
12  logical :: ret
13  integer :: fib, n
14  integer :: exit_code = 0
15
16  write(*, '("Hello from Fortran server!")')
17
18  ! Create server-side rpc conneciton using model name
19  rpc = ygg_rpc_server("server", "%d", "%d")
20
21  ! Initialize variables
22  ret = .true.
23  fib = -1
24
25  ! Continue receiving requests until the connection is closed when all
26  ! clients have disconnected.
27  do while (.TRUE.)
28     write(*, '("server(F): receiving...")')
29     ret = ygg_recv_var(rpc, yggarg(n))
30     if (.not.ret) then
31        write(*, '("server(F): end of input")')
32        exit
33     end if
34
35     ! Compute fibonacci number
36     write(*, '("server(F): Received request for Fibonacci number ",i2)') n
37     fib = get_fibonacci(n)
38     write(*, '("server(F): Sending response for Fibonacci number ",i2,": ",i2)') n, fib
39
40     ! Send response back
41     ret = ygg_send_var(rpc, yggarg(fib))
42     if (.not.ret) then
43        write(*, '("server(F): ERROR sending")')
44        exit_code = -1;
45        exit;
46     end if
47  end do
48
49  write(*, '("Goodbye from Fortran server")')
50  if (exit_code.lt.0) then
51     stop 1
52  end if
53
54end program main
55
56function get_fibonacci(n) result(out)
57  integer, intent(in) :: n
58  integer :: out
59  integer :: pprev, prev, fib_no
60  pprev = 0
61  prev = 1
62  out = 1
63  fib_no = 1
64  do while (fib_no < n)
65     out = prev + pprev
66     pprev = prev
67     prev = out
68     fib_no = fib_no + 1
69  end do
70end function get_fibonacci
 1program main
 2  use fygg
 3
 4  character(len=32) :: arg
 5  integer :: iterations
 6  type(yggcomm) :: rpc
 7  type(yggcomm) :: log
 8  logical :: ret
 9  integer :: fib, i
10  integer :: exit_code = 0
11
12  call get_command_argument(1, arg)
13  read(arg, *) iterations
14  write(*, '("Hello from Fortran client: iterations ",i2)') iterations
15
16  ! Set up connections matching yaml
17  ! RPC client-side connection will be $(server_name)_$(client_name)
18  rpc = ygg_rpc_client("server_client", "%d", "%d")
19  log = ygg_output_fmt("output_log", "fib(%-2d) = %-2d\n")
20
21  ! Initialize variables
22  ret = .true.
23  fib = -1
24
25  ! Iterate over Fibonacci sequence
26  do i = 1, iterations
27
28     ! Call the server and receive response
29     write(*, '("client(F): Calling fib(",i2,")")') i
30     ret = ygg_rpc_call(rpc, yggarg(i), yggarg(fib))
31     if (.not.ret) then
32        write(*, '("client(F): RPC CALL ERROR")')
33        exit_code = -1;
34        exit
35     end if
36     write(*, '("client(F): Response fib(",i2,") = ",i2)') i, fib
37
38     ! Log result by sending it to the log connection
39     ret = ygg_send_var(log, [yggarg(i), yggarg(fib)])
40     if (.not.ret) then
41        write(*, '("client(F): SEND ERROR")')
42        exit_code = -1
43        exit
44     end if
45
46  end do
47
48  write(*, '("Goodbye from Fortran client")')
49  if (exit_code.lt.0) then
50     stop 1
51  end if
52
53end program main

Model YAML:

1---
2
3model:
4  name: server
5  language: fortran
6  args: ./src/server.f90
7  is_server: True  # Creates a RPC server queue called "server"
 1---
 2
 3model:
 4  name: client
 5  language: fortran
 6  args:
 7    - ./src/client.f90
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True

Matlab Version

Model Code:

 1function server()
 2  
 3  disp('Hello from Matlab server!');
 4
 5  % Create server-side rpc conneciton using model name
 6  rpc = YggInterface('YggRpcServer', 'server', '%d', '%d');
 7
 8  % Continue receiving requests until the connection is closed when all
 9  % clients have disconnected.
10  while true
11    disp('server(M): receiving...');
12    [retval, rpc_in] = rpc.recv();
13    if (~retval);
14      disp('server(M):end of input');
15      break;
16    end;
17
18    % Compute fibonacci number
19    n = rpc_in{1};
20    fprintf('server(M): Received request for Fibonacci number %d\n', n);
21    pprev = 0;
22    prev = 1;
23    result = 1;
24    fib_no = 1;
25    while fib_no < n
26      result = prev + pprev;
27      pprev = prev;
28      prev = result;
29      fib_no = fib_no + 1;
30    end;
31    fprintf('server(M): Sending response for Fibonacci number %d: %d\n', n, result);
32
33    % Send response back
34    flag = rpc.send(int32(result));
35    if (~flag);
36      error('server(M): ERROR sending');
37    end;
38  end;
39
40  disp('Goodbye from Matlab server');
41  
42end
 1function client(iterations)
 2  
 3  iterations = str2num(iterations);
 4  fprintf('Hello from Matlab client: iterations = %d\n', iterations);
 5
 6  % Set up connections matching yaml
 7  % RPC client-side connection will be $(server_name)_$(client_name)
 8  rpc = YggInterface('YggRpcClient', 'server_client', '%d', '%d');
 9  log = YggInterface('YggOutput', 'output_log', 'fib(%-2d) = %-2d\n');
10
11  % Iterate over Fibonacci sequence
12  for i = 1:iterations
13    
14    % Call the server and receive response
15    fprintf('client(Matlab): Calling fib(%d)\n', i);
16    [ret, result] = rpc.call(int32(i));
17    if (~ret);
18      error('client(Matlab): RPC CALL ERROR');
19    end;
20    fib = result{1};
21    fprintf('client(Matlab): Response fib(%d) = %d\n', i, fib);
22
23    % Log result by sending it to the log connection
24    ret = log.send(int32(i), fib);
25    if (~ret);
26      error('client(Matlab): SEND ERROR');
27    end;
28  end;
29
30  disp('Goodbye from Matlab client');
31  
32end

Model YAML:

1---
2
3model:
4  name: server
5  language: matlab
6  args: ./src/server.m
7  is_server: True  # Creates a RPC server queue called "server"
 1---
 2
 3model:
 4  name: client
 5  language: matlab
 6  args:
 7    - ./src/client.m
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True

Python Version

Model Code:

 1import numpy as np
 2from yggdrasil.interface.YggInterface import YggInput, YggRpcServer
 3
 4
 5def get_fibonacci(n):
 6    r"""Compute the nth number of the Fibonacci sequence.
 7
 8    Args:
 9        n (int): Index of the Fibonacci number in the Fibonacci sequence that
10            should be returned.
11
12    Returns:
13        int: The nth Fibonacci number.
14
15    """
16    pprev = 0
17    prev = 1
18    result = 1
19    fib_no = 1
20    while fib_no < n:
21        result = prev + pprev
22        pprev = prev
23        prev = result
24        fib_no = fib_no + 1
25    return result
26
27
28def main():
29    r"""Function to execute server communication and computation in a loop."""
30
31    print('Hello from Python server!')
32
33    # Get parameters
34    inp = YggInput("params")
35    retval, params = inp.recv()
36    if not retval:
37        raise RuntimeError('server(P): ERROR receiving parameters')
38    print('server(P): Parameters = %s' % params)
39
40    # Create server-side rpc conneciton using model name
41    rpc = YggRpcServer("server", "%d", "%d")
42
43    # Continue receiving requests until the connection is closed when all
44    # clients have disconnected.
45    while True:
46        print('server(P): receiving...')
47        retval, rpc_in = rpc.recv()
48        if not retval:
49            print('server(P): end of input')
50            break
51
52        # Compute fibonacci number
53        n = rpc_in[0]
54        print('server(P): Received request for Fibonacci number %d' % n)
55        result = get_fibonacci(n)
56        print('server(P): Sending response for Fibonacci number %d: %d' % (n, result))
57
58        # Send response back
59        flag = rpc.send(np.int32(result))
60        if not flag:
61            raise RuntimeError('server(P): ERROR sending')
62
63    print('Goodbye from Python server')
64
65    
66if __name__ == '__main__':
67    main()
 1import sys
 2import numpy as np
 3from yggdrasil.interface.YggInterface import (
 4    YggRpcClient, YggOutput)
 5
 6
 7def main(iterations):
 8    r"""Function to execute client communication with server that computes
 9    numbers in the Fibonacci sequence.
10
11    Args:
12        iterations (int): The number of Fibonacci numbers to log.
13
14    """
15
16    print('Hello from Python client: iterations = %d ' % iterations)
17
18    # Set up connections matching yaml
19    # RPC client-side connection will be $(server_name)_$(client_name)
20    rpc = YggRpcClient("server_client", "%d", "%d")
21    log = YggOutput("output_log", 'fib(%-2d) = %-2d\n')
22
23    # Iterate over Fibonacci sequence
24    for i in range(1, iterations + 1):
25        
26        # Call the server and receive response
27        print('client(Python): Calling fib(%d)' % i)
28        ret, result = rpc.call(np.int32(i))
29        if not ret:
30            raise RuntimeError('client(Python): RPC CALL ERROR')
31        fib = result[0]
32        print('client(Python): Response fib(%d) = %d' % (i, fib))
33
34        # Log result by sending it to the log connection
35        ret = log.send(np.int32(i), fib)
36        if not ret:
37            raise RuntimeError('client(Python): SEND ERROR')
38
39    print('Goodbye from Python client')
40
41    
42if __name__ == '__main__':
43    # Take number of iterations from the first argument
44    main(int(sys.argv[1]))

Model YAML:

 1---
 2
 3model:
 4  name: server
 5  language: python
 6  args: ./src/server.py
 7  is_server: True  # Creates a RPC server queue called "server"
 8  inputs:
 9    name: params
10    default_file:
11      name: ./Input/server_params.txt
12      filetype: ascii
 1---
 2
 3model:
 4  name: client
 5  language: python
 6  args:
 7    - ./src/client.py
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True

R Version

Model Code:

 1library(yggdrasil)
 2
 3
 4get_fibonacci <- function(n) {
 5  pprev = 0
 6  prev = 1
 7  result = 1
 8  fib_no = 1
 9  while (fib_no < n) {
10    result = prev + pprev
11    pprev = prev
12    prev = result
13    fib_no = fib_no + 1
14  }
15  return(as.integer(result))
16}
17
18
19main <- function() {
20
21  fprintf('Hello from R server!')
22
23  # Create server-side rpc conneciton using model name
24  rpc <- YggInterface('YggRpcServer', "server", "%d", "%d")
25
26  # Continue receiving requests until the connection is closed when all
27  # clients have disconnected.
28  while (1) {
29    fprintf('server(R): receiving...')
30    c(retval, rpc_in) %<-% rpc$recv()
31    if (!retval) {
32      fprintf('server(R): end of input')
33      break
34    }
35
36    # Compute fibonacci number
37    n = rpc_in[[1]]
38    fprintf('server(R): Received request for Fibonacci number %d', n)
39    result = get_fibonacci(n)
40    fprintf('server(R): Sending response for Fibonacci number %d: %d', n, result)
41
42    # Send response back
43    flag <- rpc$send(result)
44    if (!flag) {
45      stop('server(R): ERROR sending')
46    }
47    
48  }
49
50  print('Goodbye from R server')
51}
52
53main()
 1library(yggdrasil)
 2
 3
 4main <- function(iterations) {
 5
 6  fprintf('Hello from R client: iterations = %d', iterations)
 7
 8  # Set up connections matching yaml
 9  # RPC client-side connection will be $(server_name)_$(client_name)
10  rpc <- YggInterface('YggRpcClient', "server_client", "%d", "%d")
11  log <- YggInterface('YggOutput', "output_log", 'fib(%-2d) = %-2d\n')
12
13  # Iterate over Fibonacci sequence
14  for (i in 1:iterations) {
15        
16    # Call the server and receive response
17    fprintf('client(R): Calling fib(%d)', i)
18    c(ret, result) %<-% rpc$call(i)
19    if (!ret) {
20      stop('client(R): RPC CALL ERROR')
21    }
22    fib <- result[[1]]
23    fprintf('client(R): Response fib(%d) = %d', i, fib)
24
25    # Log result by sending it to the log connection
26    ret <- log$send(i, fib)
27    if (!ret) {
28      stop('client(R): SEND ERROR')
29    }
30  }
31
32  print('Goodbye from R client')
33}
34
35
36args = commandArgs(trailingOnly=TRUE)
37main(strtoi(args[[1]]))

Model YAML:

1---
2
3model:
4  name: server
5  language: R
6  args: ./src/server.R
7  is_server: True  # Creates a RPC server queue called "server"
 1---
 2
 3model:
 4  name: client
 5  language: R
 6  args:
 7    - ./src/client.R
 8    - 3  # Pass the number of iterations that should be performed
 9  client_of: server  # Creates an RPC client queue "server_client"
10  outputs: output_log
11
12connections:
13  input: output_log
14  output: client_output.txt
15  in_temp: True