ajax 调用从 php libevent 客户端获取连续/流式数据
Posted
技术标签:
【中文标题】ajax 调用从 php libevent 客户端获取连续/流式数据【英文标题】:ajax call to get continuous/streaming data from php libevent client 【发布时间】:2016-07-29 15:18:24 【问题描述】:我正在寻找从 php libevent 客户端接收流数据的 ajax 调用或 jquery api。
Libevent 客户端将从 Libevent Server.c 接收数据
服务器.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;
编译
gcc -o Server Server.c -levent
那么Client.php就是
<?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();
?>
Client.php 只能通过 CLI 模式运行,下面是 RunClient.php
<?php
passthru('php Client.php');
?>
我有一个挑战来提出一个 ajax 调用或 jquery ajax 调用来接收来自 Client.php 的刷新数据。 JQuery ajax 或Ajax 调用不能直接调用Client.php,而是调用RunClient.php。如果有人可以尝试提供 ajax 调用或 Jquery ajax 调用来接收刷新的数据,我将不胜感激。
【问题讨论】:
在浏览器中调用 RunClient.php 会发生什么?如果您的服务器发出事件,它会立即以空白页面回答还是浏览器等待永远不会发生的事件? 在浏览器中运行时,它会等待 localhost 直到超时并出现 504 Gateway Timeout。虽然我不打算在浏览器中运行它。它只会被 ajax 调用调用。 【参考方案1】:使用浏览器进行测试是了解发生了什么的第一步。
我不熟悉 php Thread 类,但可能发生的是当你调用时
passthru('php Client.php');
在 RunClient.php 中,调用被阻塞,等待php Client.php
完成。
由于Client.php
是一个长时间运行的服务器(它基本上永远不会结束),即使你在Client.php
中使用flush()
也很难得到答案。
你可以试试
<?php
$fp = fopen('php Client.php');
fpassthru($fp);
?>
查看您是否在浏览器中看到结果(确保您的服务器发出数据)
之后,您提到要使用 ajax。您需要了解 ajax 调用有点像浏览器调用:它是请求->响应机制而不是流机制。
您可以尝试在您的 html 页面中使用脚本标签
<script src='RunClient.php'/>
并修改您的 Client.php,而不是
echo $data."\n";
与
echo "document.write('<span>".$data."</span>');\n";
和不带引号的简单数据。如果它有效,您将需要转义数据,以便发出的字符串是有效的 javascript。
当然,这是一个原型。这一切都取决于你想做什么。
您可能还想使用 websocket 进行流式传输。该协议是为流式传输而设计的。 cfhttps://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
【讨论】:
谢谢。我尝试了一切,但无法获取数据。你是对的,只要 Client.php 是一个长时间运行的服务器(它基本上永远不会结束),即使在 Client.php 中使用 flush 也不可能得到答案。我实际上想提供一个长轮询服务器来用新数据更新网页。不知何故不想使用 Websockets,因为它不适用于某些浏览器。 Libevent 或 Socket.io 将是最好的选择。请您建议我在这里使用此解决方案的最佳技巧?以上是关于ajax 调用从 php libevent 客户端获取连续/流式数据的主要内容,如果未能解决你的问题,请参考以下文章
使用 xhprof 分析 PHP 代码时,如何防止它破坏来自 JavaScript 客户端的 Ajax 调用?
PHP $connection->query($sql) 在 AJAX 调用期间从 PHP 脚本调用时返回 FALSE? [复制]