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.php
sebanyak 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 ...
sumber
EventSource('stream.php')
, klien membuka koneksistream.php
yang 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 memicustream.php
file Anda lagi.Jawaban:
Ya, dan pseudo-code Anda adalah pendekatan yang masuk akal.
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.)
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.
sumber
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
EventSource
API 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.
sumber
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!
sumber
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)_query
metode 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:
sumber
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.
sumber