[go: nahoru, domu]

Skip to content

Server calling client

This demonstrates how to simulate a C client handling a get call from a kdb+ server.

The Java interface allows you to emulate a kdb+ server. The C interface does not provide the ability to respond to a sync call from the server, however, async responses (message type 0) can be sent using k(-c,...).

A get call may be desirable when client functions need to be called by the server – as though the client were an extension. This q code shows how a listening kdb+ server can call a kdb+ client (with handle h) using async messaging only:

q)f:{neg[h]({neg[.z.w]value x};x);h[]} 
q)f"1+1"
2

Generally, async set messages to the client are preferable because the server has many clients and does not want to be blocked by a slow response from any one client. One application of simulated get from the server is where an extension might have been the solution to a problem, but an out-of-process solution was preferred because:

  • only 32-bit or 64-bit libraries were available
  • unreliable external code may stomp on kdb+
  • licensing issues
  • system calls in external code conflict with kdb+

Example

This example shows a kdb+ server operating with a single client.

The client defines a range of C functions, which are registered with the kdb+ instance and can then be susequently called remotely using the q language.

Code

sc.q

Script for kdb+ server instance

GET:{(neg h)x;x:h[];x[1]}
S:string
fs:{{eval parse s,":{GET[(`",(s:S x[0]y),";",(S y),";",(";"sv S x[1;y]#"xyz"),")]}"}[x]each til count x}
.z.po:{h::x;fs GET`}

sc.c

C code for building client application

//sc.c  server calls client with simulated GET.
// linux build instructions gcc sc.c -o sc -DKXVER=3 -lrt -pthread l64/c.o
// macOS build instructions gcc sc.c -o sc -DKXVER=3 -pthread m64/c.o
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/select.h>
#include"k.h"
#define A(x)     if(!(x))printf("A(%s)@%d\n",#x,__LINE__),exit(0);  //assert - simplistic error handling

static K home(K x){
    char* s;
    printf("%s function called\n",__FUNCTION__);
    s=getenv("HOME");
    x=ktn(KC,strlen(s));
    DO(xn,xC[i]=s[i])
    return x;
}
static K palindrome(K x){
    char c,*d;
    printf("%s function called\n",__FUNCTION__);
    A(xt==KC);
    K k=ktn(KC,xn*2);
    DO(xn,kC(k)[i]=xC[i]);
    DO(xn,kC(k)[xn+i]=xC[xn-1-i]);
    return k;
}
//exported functions and their arity
static K(*f[])()={home,palindrome,0};
static char* n[]={"home","palindrome",0};
static long long a[]={1,1};

static K d(K x){
    K k=ktn(KS,0),v=ktn(KJ,0);
    long long i=0;
    while(f[i])
        js(&k,ss(n[i])),ja(&v,a+i),i++;
    return knk(2,k,v);
}
//remote sends atom or (`palindrome;0;x) or (`home;1;)
static K call(K x){
    P(0>xt,d(0));
    A(xt==0);
    A(xn>1);
    A(xx->t==-KS);
    return f[xy->j](xK[2]);
}
static I sel(int c,double t){
    A(2<c);
    int r;
    fd_set f,*p=&f;
    FD_ZERO(p);
    FD_SET(c,p);
    long s=t,v[]={s,1e6*(t-s)};
    A(-1<(r=select(c+1,p,(V*)0,(V*)0,(V*)v)));
    P(r&&FD_ISSET(c,&f),c)
    return 0;
}
static K sr(int c){
    int t;
    K x;
    A(x=k(c,(S)0));
    return k(-c,"",call(x),(K)0);
} //async from q
int main(int n,char**v){
    int c=khp("",5001);
    while(1)
        if(c==sel(c,1e-2))
            A(sr(c));
}

Running Example

Run kdb+, listening on port 5001 using the sc.q script:

q sc.q -p 5001
on another terminal run sc to connect to the kdb+ instance.

In q, .z.po is called when sc connects. .z.po then saves the socket h and calls GET` to find the list of functions the client provides.

fs is called to eval a new function definition for home and palindrome. Then in q you can view the registered functions after sc connects:

Here is what sc.q defined when it received the list of functions from the client:

q)home
{GET[(`home;0;x)]}
q)palindrome
{GET[(`palindrome;1;x)]}

then in q, you can call these functions and see that the client C program sc executes its C functions & returns a result to kdb+

q)home[]
"/home/jack"
q)palindrome home[]
"/home/jackkcaj/emoh/"

Other uses

Consider a C client that is nothing but a TUI. It exposes ncurses functionality for a kdb+ listener. For fun, Conway’s game of Life will play out on the client application – all drawn by a q program.

Basics: Interprocess communication