开发者

register callback in one application to be retrieved in another

开发者 https://www.devze.com 2023-02-28 20:33 出处:网络
gcc 4.6.0 c89 I have type of client server application. The server some code in an event loop that will wait for an event from the client.
gcc 4.6.0 c89

I have type of client server application. The server some code in an event loop that will wait for an event from the client.

This is not a client server that will be using UDP/TCP sockets. But the client and server will be running on the same 开发者_C百科linux machine. I guess is like app1 talking to app2 running in the same server.

I know I need to use function pointers (callback) and I need to register the callbacks in client application. The server will wait for an event from the client and act accordingly.

So my design in the server would be something like this:

while(running) {
    switch(event) {
        case START_SDL:
        /* DO something */
        break;

        case DELETE_EDL:
        /* Do something */
        break;
    }
}

With this the server is running in the loop, waiting to receive events from the client. However, I am not sure how to get started.

Many thanks for any suggestions,


You should use a worker thread that waits for events from the main thread and processes them. This is a long answer and to avoid making it longer I shall omit error-checking although it is against the sixth commandment.

The task structure and the queue

Make a structure that specifies a task. I will use the generic get_task and push_task functions. In a real example thread-safe queue of tasks should be used but this would uselessly complicate the answer. I only sketched this from old programs I had laying around.

struct task {
    /* function callback */
    void (*fun)(void *);
    /* parameter to pass to callback */
    void *arg;
};

Synchronization

Use a mutex to protect the task queue and a semaphore to signal there is work to be done. Please see what I wrote above in bold.

/* this has to be initialized in main */
sem_t sem;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

The worker function

The worker function simply waits around and executes tasks when it is told.

static void *worker(void *arg)
{
    struct task t;

    /* detach */
    pthread_detach(pthread_self());

    /* loop forever */
    while (1) {
        /* block until we have work to do */
        sem_wait(&sem);

        /* we've got work to do */
        pthread_mutex_lock(&mtx);
        /* get the task */
        t = get_task();
        pthread_mutex_unlock(&mtx);

        /* we are safe now, nobody can touch t */
        /* execute the callback - here is your function pointer*/
        (*t.fun)(t.arg);
    }
    return NULL;
}

The main function

The role of the main function is to initialize stuff and to push tasks.

pthread_t t1;

/* initialize unnamed semaphore */
sem_init(&sem, 0, 0);

/* start worker thread */
if (0 != pthread_create(&t1, NULL, worker, NULL)) {
    perror("pthread_create");
    exit(1);
}

Pushing tasks

At this point the worker thread is waiting for tasks that you can push from main.

pthread_mutex_lock(&mtx);
push_task(my_task);
pthread_mutex_unlock(&mtx);

How is this server going to ever know the client is triggering events ? That is for you to decide, there are lots and lots of methods to do IPC on Unix. My suggestion would be to use a message queue.

Server message queue example

#define MSGSIZE 1024

int main()
{
    mqd_t mq;
    struct mq_attr attr;
    char message[MSGSIZE];
    int read_bytes;

    attr.mq_maxmsg = 10;
    attr.mq_msgsize = MSGSIZE;

    mq = mq_open("/queue", O_RDWR | O_CREAT, 0700, &attr);
    if ((mqd_t)-1 == mq) {
        perror("mq_open");
        exit(1);
    }

    while (1) {
        /* get message from queue */
        read_bytes = mq_receive(mq, message, MSGSIZE, NULL);
        if (-1 == read_bytes) {
            perror("mq_receive");
            exit(1);
        }

        /* do what you wish with the message */
    }
}

So in the "do what you wish" part you can call interpret the event type and push it for the worker. Sending the message from the client is trivially similar so I won't post that (if you really can't do it just ask).

These are all just (possibly broken) bits of one large puzzle. Your task is to assemble them into whatever you're building.


Unless this is a homework assignment, instead of reinventing the wheel, I'd recommend using one of the many available IPC libraries around:

  • libassuan is very lightweight and secure, used between the GnuPG components.
  • libdbus, the standard (desktop-)IPC library on Unix.
  • any number of CORBA implementations, eg. MICO, TAO, or omniORB.
  • any number of MPI implementations, e.g. LAM (nowadays OpenMPI).
  • ...


On *nix,

I would suggest using select() or poll(), or, if you really want to, threads.

On windows, this is an excellent guide to the Winsock API. I am not very experienced with Windows programming, but, as far as I know, Winsocks are the way to go for low-level socket IO.

EDIT;

I see the comments and apparently you are using Linux and threads.

Firstly, let me tell you that threads are not easy to work with since you have to prevent two threads from accessing the same data at the same time, etc.

However, it is definitely possible.

If you are just doing this as a learning exercise, I would suggest making a centralized set of data (which all threads access) that is mutex-ed and create a thread for every connection.

If you are under a production environment, things are not so easy. Firstly, I would suggest you read this. Then, consider thread pooling. Basically, you start with a bunch of threads (i.e. a pool) and then complete tasks as you go. A very good description can be found on wikipedia. And, the PDF I linked shows other ways as well.

If you don't want to use thread after reading all this, I would still recomment select() and poll(), they are very easy to use.

The actual code itself should be very simple considering you have basic pthreads working.


One server process with one client process.. looks like Producer - Consumer relationship. This is handled easily with pipes.

bash# client | server 

Your client writes events to stdout, server reads from stdin. If you need more then one client, then see mmutz's answer


I don't know much about C or C++ but In java I would use Future Task with the combination of Non-Blocking IO as a solution to this problem. Kindly have a look just for an idea.

0

精彩评论

暂无评论...
验证码 换一张
取 消