Websocketd 将标准输入(stdin)和标准输出(stdout)作为数据的输入和输出接口,也就是说可以使用任意语言写后台脚本。
使用 PHP 编写简单的聊天服务器脚本 chat.php:
#!/usr/bin/php
$stdin = fopen('php://stdin', 'r');
$filename = __DIR__.'/chat.log';
echo 'Please enter your name:'.PHP_EOL;
$user = trim(fgets($stdin));
$message = '['.date('Y-m-d H:i:s').'] '.$user.' joined the chat'.PHP_EOL;
file_put_contents($filename, $message, FILE_APPEND);
echo '['.date('Y-m-d H:i:s').'] Welcome to the chat '.$user.'!'.PHP_EOL;
$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == - 1 ) {
die( 'could not fork' );
} else if ($pid) {
while ($msg = fgets($stdin)) {
$message = '['.date('Y-m-d H:i:s').'] '.$user.' '.$msg.PHP_EOL;
file_put_contents($filename, $message, FILE_APPEND);
}
pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
$lastmtime = null;
$ftell = null;
// 子进程得到的 $pid 为 0
while (1) {
$fp = fopen($filename, 'r');
if ($fp) {
$fstat = fstat($fp);
$mtime = $fstat['mtime'];
if (!$lastmtime) {
fseek($fp, 0, SEEK_END);
$lastmtime = $mtime;
$ftell = ftell($fp);
} else if ($lastmtime < $mtime) {
$lastmtime = $mtime;
fseek($fp, $ftell);
while (!feof($fp) && ($line = fgets($fp, 4096)) !== false ) {
echo $line;
}
$ftell = ftell($fp);
}
fclose($fp);
}
sleep(1);
}
}
启动 websocketd:
./websocketd --port=8080 php chat.php
客户端 chat.html:
websocketd chat example发送
var ws = new WebSocket('ws://localhost:8080/');
ws.onopen = function() {
document.body.style.backgroundColor = '#cfc';
document.getElementById('messageList').innerHTML += '已连接
';
};
ws.onclose = function() {
document.body.style.backgroundColor = null;
};
ws.onmessage = function(event) {
document.getElementById('messageList').innerHTML += event.data + '
';
};
ws.onerror = function(event) {
document.getElementById('messageList').innerHTML += '发送异常
';
};
document.getElementById('sendBtn').onclick = function(){
ws.send(document.getElementById('message').value);
document.getElementById('message').value = '';
};
然后在火狐打开多个 chat.html,便可以实现互发消息了。