Peristiwa dan php yang dikirim server - apa yang memicu peristiwa di server?

93

Semua,

HTML5 Rocks memiliki tutorial pemula yang bagus tentang Server-sent Events (SSE):

http://www.html5rocks.com/en/tutorials/eventsource/basics/

Namun, saya tidak memahami konsep penting - apa yang memicu peristiwa di server yang menyebabkan pesan terkirim?

Dengan kata lain - dalam contoh HTML5 - server hanya mengirimkan stempel waktu satu kali :

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));

Jika saya sedang membuat contoh praktis - misalnya, "dinding" bergaya Facebook atau ticker saham, di mana server akan "mendorong" pesan baru ke klien setiap kali beberapa bagian data berubah, bagaimana cara kerjanya?

Dengan kata lain ... Apakah skrip PHP memiliki loop yang berjalan terus menerus, memeriksa perubahan dalam data, lalu mengirim pesan setiap kali ditemukan? Jika ya - bagaimana Anda tahu kapan harus mengakhiri proses itu?

Atau - apakah skrip PHP hanya mengirim pesan, lalu diakhiri (seperti yang terlihat pada contoh HTML5Rocks)? Jika demikian - bagaimana Anda mendapatkan pembaruan berkelanjutan? Apakah browser hanya memeriksa halaman PHP secara berkala? Jika demikian - bagaimana bisa disebut "event server-sent"? Apa bedanya dengan menulis fungsi setInterval di JavaScript yang menggunakan AJAX untuk memanggil halaman PHP pada interval reguler?

Maaf - ini mungkin pertanyaan yang sangat naif. Tapi tidak ada contoh yang bisa saya temukan yang menjelaskan hal ini.

[MEMPERBARUI]

Saya pikir pertanyaan saya kurang tepat, jadi inilah beberapa klarifikasinya.

Katakanlah saya memiliki halaman web yang seharusnya menampilkan harga saham Apple terbaru.

Saat pengguna pertama kali membuka halaman, halaman membuat EventSource dengan URL "aliran" saya.

var source = new EventSource('stream.php');

Pertanyaan saya adalah - bagaimana seharusnya "stream.php" bekerja?

Seperti ini? (pseudo-code):

<?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
    function sendMsg($msg) {
        echo "data: $msg" . PHP_EOL;
        echo PHP_EOL;
        flush();
    }

    while (some condition) {
        // check whether Apple's stock price has changed
        // e.g., by querying a database, or calling a web service
        // if it HAS changed, sendMsg with new price to client
        // otherwise, do nothing (until next loop)
        sleep (n) // wait n seconds until checking again
    }
?>

Dengan kata lain - apakah "stream.php" tetap terbuka selama klien "terhubung" dengannya?

Jika demikian - apakah itu berarti Anda memiliki banyak utas yang berjalan stream.phpsebanyak Anda memiliki pengguna bersamaan? Jika demikian - apakah itu memungkinkan, atau cara yang tepat untuk membangun aplikasi? Dan bagaimana Anda tahu kapan Anda bisa MENGAKHIRI sebuah instance stream.php?

Kesan naif saya adalah, jika ini masalahnya, PHP bukanlah teknologi yang cocok untuk jenis server ini. Tetapi semua demo yang saya lihat sejauh ini menyiratkan bahwa PHP baik-baik saja untuk ini, itulah sebabnya saya sangat bingung ...

mattstuehler
sumber
Itulah bagian yang harus dikodekan oleh pengembang sendiri. Cara mendapatkan data adalah melalui websockets / long polling dll. Namun triknya adalah yang memicu acara tersebut. Secara pribadi, saya telah bereksperimen dengan beberapa pendekatan dan satu pendekatan yang saya suka (tetapi tidak terlalu aman) adalah membuat MySQL memicu program konsol setiap kali ada sesuatu yang dimasukkan ke dalam tabel tertentu. Program konsol akan menerima info tentang catatan yang diubah / dimasukkan dan itu akan mengirim pemberitahuan ke pengguna yang sesuai melalui WebSockets. Pada dasarnya saya memiliki daemon PHP yang menunggu untuk mengirim pesan.
NB
Satu masalah dengan ini, SSE tidak didukung oleh IE: - / Saya juga akan membaca prodigyproductionsllc.com/articles/programming/javascript/… Saya pikir dia menggunakan port untuk menghindari masalah terlalu banyak anak tetapi secara keseluruhan terlihat seperti miliknya rekomendasinya adalah untuk menghindari SSE. Sepertinya lebih banyak masalah daripada nilainya, IMO.
PJ Brunet
Saat ini tidak didukung oleh IE11 atau Browser Android caniuse.com/eventsource
PJ Brunet
1
Jika seseorang membutuhkan kode php sse: github.com/shahzadthathal/server-sent-events-php-example
Muhammad Shahzad
4
Saya punya pertanyaan yang sama dan saya pikir saya sangat mengerti apa yang Anda maksud dengan apa yang memicu peristiwa di server ... . Saat Anda membuat objek EventSource('stream.php'), klien membuka koneksi stream.phpyang seperti memanggilnya dengan ajax. Koneksi INI memicu kode sisi server Anda dan membuat koneksi tetap terbuka selama kode sisi server Anda mengatakan sesuatu. Kemudian koneksi ditutup dan setelah penundaan singkat (3 detik di chrome saya pikir) klien membuka kembali koneksi yang memicu stream.phpfile Anda lagi.
Ahmad Maleki

Jawaban:

29

"... apakah" stream.php "tetap terbuka selama klien" terhubung "dengannya?"

Ya, dan pseudo-code Anda adalah pendekatan yang masuk akal.

"Dan bagaimana Anda tahu kapan Anda bisa MENGAKHIRI sebuah instance dari stream.php?"

Dalam kasus yang paling umum, ini terjadi saat pengguna meninggalkan situs Anda. (Apache mengenali soket tertutup, dan mematikan instance PHP.) Waktu utama Anda menutup soket dari sisi server adalah jika Anda tahu tidak akan ada data untuk sementara waktu; pesan terakhir yang Anda kirim ke klien adalah memberi tahu mereka untuk kembali pada waktu tertentu. Misalnya dalam kasus streaming saham Anda, Anda dapat menutup koneksi pada jam 8 malam, dan memberi tahu klien untuk kembali dalam 8 jam (dengan asumsi NASDAQ terbuka untuk penawaran dari jam 4 pagi hingga 8 malam). Jumat malam Anda memberi tahu mereka untuk kembali Senin pagi. (Saya memiliki buku yang akan datang tentang SSE, dan mendedikasikan beberapa bagian tentang subjek ini.)

"... jika ini masalahnya, PHP bukanlah teknologi yang cocok untuk jenis server ini. Tetapi semua demo yang saya lihat sejauh ini menyiratkan bahwa PHP baik-baik saja untuk ini, itulah mengapa saya sangat bingung..."

Nah, orang-orang berpendapat bahwa PHP bukanlah teknologi yang cocok untuk situs web normal, dan mereka benar: Anda dapat melakukannya dengan memori dan siklus CPU yang jauh lebih sedikit jika Anda mengganti seluruh tumpukan LAMP Anda dengan C ++. Namun, meskipun demikian, PHP memberdayakan sebagian besar situs di luar sana dengan baik. Ini adalah bahasa yang sangat produktif untuk pekerjaan web, karena kombinasi sintaks C-like yang sudah dikenal dan begitu banyak perpustakaan, dan bahasa yang nyaman bagi manajer karena banyak programmer PHP yang bisa disewa, banyak buku dan sumber daya lainnya, dan beberapa yang besar. kasus penggunaan (misalnya Facebook dan Wikipedia). Itu pada dasarnya adalah alasan yang sama Anda mungkin memilih PHP sebagai teknologi streaming Anda.

Penyiapan umum tidak akan menjadi satu koneksi ke NASDAQ per instance PHP. Sebaliknya, Anda akan memiliki proses lain dengan satu koneksi ke NASDAQ, atau mungkin satu koneksi dari setiap mesin di cluster Anda ke NASDAQ. Itu kemudian mendorong harga ke server SQL / NoSQL, atau ke memori bersama. Kemudian PHP hanya mengumpulkan memori bersama (atau database), dan mendorong data keluar. Atau, miliki server pengumpulan data, dan setiap instance PHP membuka koneksi soket ke server itu. Server pengumpul data mendorong pembaruan ke masing-masing klien PHP-nya, saat menerima mereka, dan mereka pada gilirannya mendorong data itu ke klien mereka.

Masalah skalabilitas utama dengan menggunakan Apache + PHP untuk streaming adalah memori untuk setiap proses Apache. Saat Anda mencapai batas memori perangkat keras, buat keputusan bisnis untuk menambahkan mesin lain ke kluster, atau hentikan Apache, dan tulis server HTTP khusus. Yang terakhir ini dapat dilakukan dalam PHP sehingga semua pengetahuan dan kode yang ada dapat digunakan kembali, atau Anda dapat menulis ulang seluruh aplikasi dalam bahasa lain. Pengembang murni dalam diri saya akan menulis server HTTP berdedikasi dan efisien di C ++. Manajer dalam diri saya akan menambahkan kotak lain.

Darren Cook
sumber
Karena setiap proses koneksi Apache menggunakan memori, apakah lebih baik menggunakan Nginx?
Zhang Buzz
@ZhangBuzz Di mana saya mengatakan Apache + PHP itu benar-benar berarti "web-server + proses PHP", jadi pada dasarnya tidak ada perbedaan dengan menggunakan server web yang berbeda.
Darren Cook
Mungkin server seperti ini? github.com/hoaproject/Eventsource atau github.com/hhxsv5/php-sse
Enrique
Perhatikan juga bahwa Nginx bisa jauh lebih efisien untuk ini karena menggunakan lebih sedikit memori: blog.webfaction.com/2008/12/…
Enrique
32

Peristiwa yang dikirim server adalah untuk pembaruan waktu nyata dari sisi server ke sisi klien. Dalam contoh pertama, koneksi dari server tidak disimpan dan klien mencoba untuk terhubung lagi setiap 3 detik dan membuat kejadian yang dikirim server tidak ada perbedaan pada polling ajax.

Jadi, untuk membuat koneksi tetap ada, Anda perlu membungkus kode Anda dalam satu lingkaran dan memeriksa pembaruan secara konstan.

PHP berbasis thread dan semakin banyak pengguna yang terhubung akan membuat server kehabisan sumber daya. Ini dapat diselesaikan dengan mengontrol waktu eksekusi skrip dan mengakhiri skrip bila melebihi jumlah waktu (yaitu 10 menit). The EventSourceAPI akan secara otomatis tersambung lagi sehingga penundaan itu dalam rentang yang dapat diterima.

Selain itu, lihat pustaka PHP saya untuk acara yang dikirim server , Anda dapat memahami lebih lanjut tentang cara melakukan acara yang dikirim server di PHP dan membuatnya lebih mudah untuk membuat kode.

Licson
sumber
5
Bisakah Anda menguraikan lebih lanjut tentang "Ini dapat diselesaikan dengan mengontrol waktu eksekusi skrip dan mengakhiri skrip jika melebihi jumlah waktu"? Jika Anda memiliki jumlah pengguna yang berlebihan, apakah ini benar-benar akan meningkatkan penggunaan sumber daya dengan menutup koneksi karena pengguna hanya akan terhubung lagi dalam 3 detik?
Lukas
4

Saya perhatikan bahwa sse techink mengirimkan setiap beberapa data tunda ke klien (sesuatu seperti membalikkan techink data penggabungan dari halaman klien ex data penyatuan Ajax.) Jadi untuk mengatasi masalah ini saya membuat ini di halaman sseServer.php:

<?php
        session_start();
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache'); // recommended to prevent caching of event data
        require 'sse.php';
        if ($_POST['message'] != ""){
                $_SESSION['message'] = $_POST['message'];
                $_SESSION['serverTime'] = time();
        }
        sendMsg($_SESSION['serverTime'], $_SESSION['message'] );
?>

dan sse.php adalah:

<?php
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
?>

Perhatikan bahwa di sseSerer.php saya memulai sesi dan menggunakan variabel sesi! untuk mengatasi masalah tersebut.

Saya juga memanggil sseServer.php melalui Ajax (memposting dan menetapkan nilai ke variable message) setiap kali saya ingin "memperbarui" pesan.

Sekarang di jQuery (javascript) saya melakukan sesuatu seperti itu: 1st) saya mendeklarasikan variabel global var timeStamp = 0; 2) saya menggunakan algoritma berikutnya:

if(typeof(EventSource)!=="undefined"){
        var source=new EventSource("sseServer.php");
        source.onmessage=function(event)
        if ((timeStamp!=event.lastEventId) && (timeStamp!=0)){
                /* this is initialization */
                timeStamp=event.lastEventId;
                $.notify("Please refresh "+event.data, "info");
        } else {
                if (timeStamp==0){
                         timeStamp=event.lastEventId;
                }
        } /* fi */

} else {
        document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
} /* fi */

Di baris: $.notify("Please refresh "+event.data, "info"); apakah Anda dapat menangani pesan tersebut.

Untuk kasus saya, saya biasa mengirim notifikasi jQuery.

Anda dapat menggunakan POSIX PIPES atau Tabel DB untuk meneruskan "pesan" melalui POST karena sseServer.php melakukan sesuatu seperti "loop tak terbatas".

Masalah saya saat ini adalah bahwa kode di atas TIDAK MENGIRIMKAN "pesan" ke semua klien tetapi hanya ke pasangan (klien yang disebut sseServer.php berfungsi sebagai individu untuk setiap pasangan) jadi saya akan mengubah technik dan menjadi Pembaruan DB dari halaman yang saya ingin memicu "pesan" dan kemudian sseServer.php sebagai gantinya untuk mendapatkan pesan melalui POST itu akan mendapatkannya dari tabel DB.

Saya harap saya punya bantuan!

c.chasapis
sumber
3

Ini benar-benar pertanyaan struktural tentang aplikasi Anda. Peristiwa waktu nyata adalah sesuatu yang ingin Anda pikirkan sejak awal, sehingga Anda dapat merancang aplikasi Anda di sekitarnya. Jika Anda telah menulis aplikasi yang hanya menjalankan sekumpulan mysql(i)_querymetode acak menggunakan kueri string dan tidak meneruskannya melalui perantara apa pun, sering kali Anda tidak punya pilihan selain menulis ulang sebagian besar aplikasi Anda, atau melakukannya polling sisi server yang konstan.

Namun, jika Anda mengelola entitas Anda sebagai objek dan meneruskannya melalui semacam kelas perantara, Anda dapat menghubungkannya ke dalam proses itu. Lihat contoh ini:

<?php
class MyQueryManager {
    public function find($myObject, $objectId) {
        // Issue a select query against the database to get this object
    }

    public function save($myObject) {
        // Issue a query that saves the object to the database
        // Fire a new "save" event for the type of object passed to this method
    }

    public function delete($myObject) {
        // Fire a "delete" event for the type of object
    }
}

Dalam aplikasi Anda, saat Anda siap untuk menyimpan:

<?php
$someObject = $queryManager->find("MyObjectName", 1);
$someObject->setDateTimeUpdated(time());
$queryManager->save($someObject);

Ini bukan contoh yang paling bagus tetapi harus berfungsi sebagai blok bangunan yang layak. Anda dapat menghubungkan ke lapisan persistensi Anda yang sebenarnya untuk menangani pemicuan peristiwa ini. Kemudian Anda mendapatkannya segera (secepat mungkin) tanpa memalu server Anda (karena Anda tidak perlu terus-menerus menanyakan database Anda dan melihat apakah ada yang berubah).

Anda jelas tidak akan menangkap perubahan manual ke database dengan cara ini - tetapi jika Anda melakukan sesuatu secara manual ke database Anda dengan frekuensi apa pun, Anda harus:

  • Perbaiki masalah yang mengharuskan Anda melakukan perubahan manual
  • Bangun alat untuk mempercepat proses, dan jalankan peristiwa ini
Colin M
sumber
3
Colin - terima kasih atas jawaban Anda. Salah saya - pertanyaan saya tidak jelas - tetapi sebenarnya bukan ini yang saya tanyakan. Apa yang saya dimaksudkan untuk meminta ini ... Jika Anda menggunakan PHP sebagai "server" Anda - tidak script PHP Anda menelepon dari EventSource yang membutuhkan klien Anda untuk menjalankan seluruh waktu klien terhubung untuk itu? Apakah itu berarti, jika Anda memiliki 1.000 pengguna bersamaan, Anda memiliki 1.000 utas terpisah yang menjalankan 1.000 kejadian bersamaan dari skrip PHP Anda? Apakah itu layak? Dan, bagaimana Anda tahu kapan harus mengakhiri skrip php (dengan asumsi itu perulangan untuk tetap "hidup")?
mattstuehler
-7

Pada dasarnya PHP bukanlah tekonologi yang cocok untuk hal-hal semacam ini. Ya, Anda bisa membuatnya berhasil, tetapi itu akan menjadi bencana dengan beban tinggi. Kami menjalankan server saham yang mengirim sinyal perubahan saham melalui websockets ke puluhan ribu pengguna - dan Jika kami menggunakan php untuk itu ... Ya, kami bisa, tetapi siklus buatan sendiri itu - hanyalah mimpi buruk. Setiap koneksi tunggal akan membuat proses terpisah di server atau Anda harus menangani koneksi dari beberapa jenis database.

Cukup gunakan nodejs dan socket.io. Ini akan memudahkan Anda memulai dan menjalankan server dalam beberapa hari. Nodejs juga memiliki keterbatasan, tetapi untuk koneksi websockets (dan SSE) sekarang ini adalah teknologi yang paling kuat.

Dan juga - SSE tidak sebagus kelihatannya. Satu-satunya keuntungan untuk websockets - adalah bahwa paket sedang di-gzip secara asli (ws tidak di-gzip), tetapi sisi negatifnya adalah SSE adalah koneksi satu sisi. Anda pengguna, jika dia ingin menambahkan simbol saham lain ke subskripton, harus membuat permintaan ajax (termasuk semua masalah dengan kontrol asal dan permintaan akan lambat). Di websockets klien dan memutuskan berkomunikasi dua arah dalam satu koneksi terbuka, jadi jika pengguna mengirim sinyal perdagangan atau berlangganan kutipan, dia hanya mengirim string di koneksi yang sudah terbuka. Dan itu cepat.

Prosto Trader
sumber
2
Anda dapat menggunakan React.php pada dasarnya dengan cara yang sama seperti event-loop di node.js.
Matěj Koubík
3
Meskipun bagus untuk mengatakan bahwa PHP bukanlah pilihan terbaik, saya pikir Anda setidaknya harus menyertakan sesuatu yang diminta OP.
Nishchal Gautam