6

我正在读取 linux 中的一个文件,该文件是一个日志文件,它不断更新文件已更改的天气并将其输出到网页。我使用 php inotify 来做,但我的问题是它被阻塞了。

如何使 php inotify 非阻塞,以便在监视文本文件时可以做其他事情?

<?php

$fd = inotify_init();


$watch_descriptor = inotify_add_watch($fd, '/tmp/temp.txt', IN_MODIFY);


touch('/tmp/temp.txt');


    $events = inotify_read($fd);

    $contents = file_get_contents('/tmp/temp.txt');
    echo $contents;


inotify_rm_watch($fd, $watch_descriptor);
fclose($fd)

?>

或者我可以在java中做到这一点吗?..谢谢。

4

5 回答 5

7

是的你可以。你看手册了吗?它提供了非阻塞事件回调示例?如果此答案不能充分回答您,请添加更多信息。

http://php.net/manual/en/function.inotify-init.php

// Open an inotify instance
$fd = inotify_init();

// - Using stream_set_blocking() on $fd
stream_set_blocking($fd, 0);

// Watch __FILE__ for metadata changes (e.g. mtime)
$watch_descriptor = inotify_add_watch($fd, __FILE__, IN_ATTRIB);

// generate an event
touch(__FILE__);

// this is a loop
while(true){

  $events = inotify_read($fd); // Does no block, and return false if no events are pending  

  // do other stuff here, break when you want...
}

// Stop watching __FILE__ for metadata changes
inotify_rm_watch($fd, $watch_descriptor);

// Close the inotify instance
// This may have closed all watches if this was not already done
fclose($fd);
于 2012-10-29T15:47:44.017 回答
2

就像莱克说的那样。你可以让它阻塞或非阻塞。如果它是非阻塞的,你必须轮询。我认为您想要的是以多线程方式阻塞。一个线程以阻塞或非阻塞、频繁轮询模式工作,而另一个线程则执行其他操作。

于 2012-12-07T11:02:02.383 回答
1

我建议通过使用这件事会容易得多node.js.

您只需要以下代码:(文件名:watch.js)

    var fs = require('fs');
    var file = '/tmp/temp.txt/';
    fs.watchFile(file, function (curr, prev) {
        console.log('the current mtime is: ' + curr.mtime);
        console.log('the previous mtime was: ' + prev.mtime);
    });

然后你可以运行它:

    node watch.js

它将持续运行。

使用node.jsjavascript编写server-side程序,它有non-blocking I/O模型。它可以帮助您轻松完成此类事情。

这是一些相关文件fs.watchFile

于 2013-07-18T03:48:43.937 回答
1

你可以看看 React 库,它在 PHP 中提供了一个基于反应器模式的事件驱动、非阻塞 I/O Api: http ://reactphp.org/

于 2013-07-19T10:10:46.657 回答
1

我对这样的事情的偏好是使用 Java,因为我发现像你描述的那样管理后台任务更容易。

后端

我的方法是使用 Java EE 创建一个实现调度程序服务的单例启动线程。使用单例启动线程的原因是您的作业可以作为后台进程运行,因此是非阻塞的,从而为应用程序的其余部分释放资源。也可以使用简单地调用类上的方法来访问线程。您可以安排任务每隔“n”秒/分钟等读取您的文件以获取任何更新,然后可以将这些更新提供给您的前端。

基本示例:

@Singleton
@Startup
public class Scheduler {

    private static int count = 0;
    private Weather weather;

    public Weather getWeather() {
        return weather;
    }

    @PostConstruct
    public void onStartup() {
        System.out.println("Initialization success.");
    }

   @Schedule(second="*/10", minute="*", hour="*")
   public void execute() {

      byte[] encoded = Files.readAllBytes(Paths.get("weather_updates.txt"));
      String weatherUpdateStr = encoding.decode(ByteBuffer.wrap(encoded)).toString();

      weather = new Weather();
      weather.parse(weatherUpdateStr);

      // Possible addition of logic for push to web socket
   }
}

这个基本示例会在您的 Web 应用程序容器(我建议使用 JBoss 7)启动时创建一个 sigleton 线程。然后它会创建一个每 10 秒执行一次的计划任务。提供的代码将基本的 Java 7 文件读取到字符串,并且weather.parse()应该包含一些将字符串转换为 Weather 对象的逻辑。然后,天气对象就可以通过 Web 套接字推送或通过前端的一些 AJAX 请求进行轮询。

前端

我会在这里建议两种可能的方法:

  1. 使用 HTML5 的 Web 套接字
  2. AJAX 调用

1.网络套接字

Web 套接字被引入 HTML5 作为一种在页面上提供动态内容而无需刷新或使用 AJAX 调用的方式。是对 HTML5 中的 websockets 的一个很好的介绍。这是另一个如何使用 Java 设置 HTML5 websockets 的好例子

2. AJAX 调用

jQuery 为 AJAX 提供了一个很棒的 AP​​I。你可以在 jQuery 中实现一个Timeout任务,它会间歇性地执行一些功能。您将要实现的功能是AJAX Get request

基本示例:

$.ajax({
    url: "getWeatherUpdate.html",
    error: function(){
        // will fire when timeout is reached
    },
    success: function(){
        // Update your webpage with weather info
    },
    timeout: 3000 // sets timeout to 3 seconds
});
于 2013-07-18T20:53:25.037 回答