简体   繁体   中英

ajax call to get continuous/streaming data from php libevent client

I am looking for which ajax call or jquery api to be receiving streaming data from php libevent client.

The Libevent Client will be receiving data from Libevent Server.c

Server.c

/* For socket functions */
#include <sys/socket.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/un.h>
#include <event2/listener.h>

#include <arpa/inet.h>

#include <signal.h>

#define MAX_LINE 16384

void readcb(struct bufferevent *bev, void *ctx)
{
  /* This callback is invoked when there is data to read on bev. */
  struct evbuffer *input = bufferevent_get_input(bev);
  int len = evbuffer_get_length(input);
  char *data;
  data = malloc(len);
  evbuffer_copyout(input, data, len);
  free(data);
}

void writecb(struct bufferevent *bev, void *ctx)
{
  //here i will be checking my database and memcache new updates
  //it will wait randomly between 2 to 6 seconds to check again

  char *message = "Continuous message from your Server";
  evbuffer_add(bufferevent_get_output(bev), message, strlen(message));
  sleep(2+rand()%4);
}

void errorcb(struct bufferevent *bev, short error, void *ctx)
{
  if (error & BEV_EVENT_EOF) {
    /* connection has been closed, do any clean up here */
    /* ... */
  } else if (error & BEV_EVENT_ERROR) {
    /* check errno to see what error occurred */
    /* ... */
  } else if (error & BEV_EVENT_TIMEOUT) {
    /* must be a timeout event handle, handle it */
    /* ... */
  }
  bufferevent_free(bev);
}

void do_accept(evutil_socket_t listener, short event, void *arg)
{
  struct event_base *base = arg;
  struct sockaddr_storage ss;
  socklen_t slen = sizeof(ss);
  int fd = accept(listener, (struct sockaddr*)&ss, &slen);
  if (fd < 0) {
    perror("accept");
  } else if (fd > FD_SETSIZE) {
    close(fd);
  } else {
    struct bufferevent *bev;
    evutil_make_socket_nonblocking(fd);
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, readcb, writecb, errorcb, NULL);
    bufferevent_setwatermark(bev, EV_READ, 0, MAX_LINE);
    bufferevent_enable(bev, EV_READ|EV_WRITE);
  }
}

void run(void)
{
  evutil_socket_t listener;
  struct sockaddr_un sun;
  int len;
  struct event_base *base;
  struct event *listener_event;
  base = event_base_new();

  if (!base)
    return; /*XXXerr*/

  listener = socket(AF_UNIX, SOCK_STREAM, 0);
  evutil_make_socket_nonblocking(listener);

#ifndef WIN32
{
    int one = 1;
    setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif

  memset(&sun, 0, sizeof(sun));

  sun.sun_family = AF_UNIX;
  strcpy(sun.sun_path, "/tmp/influenzaunix.sock");

  unlink(sun.sun_path);
  len = strlen(sun.sun_path) + sizeof(sun.sun_family);
  if (bind(listener, (struct sockaddr *)&sun, len) < 0) {
    perror("bind");
    return;
  }

  if (listen(listener, 16)<0) {
    perror("listen");
    return;
  }

  listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);

  event_add(listener_event, NULL);

  event_base_dispatch(base);
}

int main(int c, char **v)
{
  setvbuf(stdout, NULL, _IONBF, 0);

  run();
  return 0;
}

Compiled with

gcc -o Server Server.c -levent

Then the Client.php is

<?php
define('MAX_LINE', '16384');
define('CHUNK_SIZE', '128');

class Server extends Thread{
    public function run(){
        passthru('./Server');
    }
}

class Client extends Thread{

    public function readcb($bev, $ctx)
    {
        $tmp = array();

        while (1) {
            $data = event_buffer_read($bev,CHUNK_SIZE);
            $size = strlen($data);
            if($size <= 0)
                break;
            $tmp[] = $data;
        }
        $data = implode($tmp);
        echo $data."\n"; //display the data received from server
        flush(); /*flush the data so that an ajax call will be receiving it*/
    }

    public function eventcb($bev, $events, $ptr)
    {
    }

    public function run()
    {
        $sockpath = '/tmp/influenzaunix.sock';
        $socket = stream_socket_client("unix://{$sockpath}",$errorNumber,$errorString,STREAM_CLIENT_CONNECT);
        stream_set_blocking($socket, 0); //non-blocking mode

        if (($socket) === FALSE){
            echo 'connect error';
        }
        else{
            $message = "Send data about this topic"; //subscribing to get data about a topic
            $bev = event_buffer_new($socket, array($this,"readcb"), NULL, array($this,"eventcb"));

            $base = event_base_new();

            if($base !== FALSE)
            {
                event_buffer_base_set($bev,$base);
                event_buffer_enable($bev, EV_READ|EV_WRITE);
                event_buffer_write($bev, $message, strlen($message));
            }

            event_base_loop($base);
        }
    }
}

$server = new Server();
$server->start();

sleep(3); /*let's wait for 3 seconds to make sure Server is ready to accept connection*/    

$client = new Client();
$client->start();
?>

The Client.php can only be run via CLI mode with RunClient.php below

<?php
passthru('php Client.php');
?>

I am having a challenge to come up with an ajax call or jquery ajax call to be receiving the flushed data from Client.php. The JQuery ajax or Ajax call cannot call Client.php directly instead it will call RunClient.php. Please I will greatly appreciate if someone can make an attempt to provide an ajax call or Jquery ajax call to be receiving the flushed data.

Testing with a browser is a first step to understand what is happening.

I am not familiar with php Thread class, but what may be happening is that when you call

passthru('php Client.php');

in RunClient.php, the call is blocking, waiting for php Client.php to finish.

Since Client.php is a long running server (it basically never ends), you never get an answer even tough you used flush() inside Client.php .

You may want to try

<?php
$fp = fopen('php Client.php');
fpassthru($fp);
?>

to see if you see results in the browser (make sure your server emits data)

After that, you mention that you want to use ajax. You need to understand that an ajax call is a bit like a browser call : it is a request->response mechanism and not a streaming mechanism.

you can try maybe with a script tag in your html page

<script src='RunClient.php'/>

and modify your Client.php, instead of

echo $data."\n";

with

echo "document.write('<span>".$data."</span>');\n";

and simple datas without quotes. If it works, you will need to escape the data so that the emitted string is valid javascript.

Of course, this is a prototype. It all depends on what you want to do.

You may also want to use websockets for streaming. The protocol is made for streaming. cf https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM