主要实现了群聊功能
原理很简单:
本地(javascript)向服务器发送消息(图片或者文字),由服务器(php)向各个主机转发
上传图片由ajax和html5实现,可以参考我之前的博客Html5&Ajax实现文件后台上传
暂时还未区分用户姓名、ip、时间等信息(不过这都是很简单的)
需要建立一个名称为file的文件夹存储上传的图片,server.php 后台运行(php server.php)
index.html
DEMO
function GetXmlHttpObject()
//根据不同浏览器获取XmlHttp对象
{
var xmlHttp=null;
try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
function esc(da){
//转义了
da=da.replace(//g,'>').replace(/\"/g,'"');
return encodeURIComponent(da);
}
function send_pic()
{
var xx = document.getElementById("file").files[0];
if (so == null)
{
alert('未连接服务器');
return;
}
if (xx == null)
{
alert('未选择图片');
return;
}
var fd = new FormData() //FormData 顾名思义,表单也
//表单中添加项,当然也可以添加别的,比如 fd.append('author', 'kkk')
fd.append('file', xx)
var xhr = GetXmlHttpObject();//这里不直接用new XMLHttpRequest()避免浏览器不兼容
if (xhr == null)
{
alert ("Browser does not support HTTP Request")
return
}
//注意!! 如果fd的append的值是文件
//在trans.php中$_POST数组将看不到该属性
//而应该在$_FILES中查看!!
xhr.open("POST" ,"./trans.php" , true);
xhr.send(fd);
xhr.onload = function(e) {
if (this.status == 200) {
so.send("nr=" + esc(this.responseText) + "&type=img")
//清空input 的值
var oldFile = document.getElementById("file");
var newFile = document.createElement("input");
newFile.id = oldFile.id;
newFile.type = "file";
oldFile.parentNode.replaceChild(newFile, oldFile);
}
};
}
run();
class Sock
{
public $master;
public $sockets; //存放所有的socket 包括 $master
public function __construct($address, $port)
{
//create a socket
$this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
//bind socket with address and port
socket_bind($this->master, $address, $port);
//listen!
socket_listen($this->master);
$this->sockets = array($this->master); //put master into sockets
echo ('Server Started : '.date('Y-m-d H:i:s') ."\n");
echo ('Listening on : '.$address.' port '.$port ."\n");
}
function run()
{
while (true)
{
$changes=$this->sockets; //准备监听所有sockets的变化
$write = NULL;
$except = NULL;
socket_select($changes, $write, $except, NULL);
foreach ($changes as $sock)
{
if ($sock == $this->master)
//如果$master发生变化,代表有新的socket连接
{
$client = socket_accept($sock);
$this->add_user($client);
$this->handshake($client);
}
else{
$msg = $this->get_message($sock);
if ($msg == '')
continue;
parse_str($msg, $ar);
$str = $this->code(json_encode($ar));
foreach ($this->sockets as $client)
{
//向除了服务器本身之外的所有套接字发送消息
if ($client == $this->master)
continue;
socket_write($client, $str, strlen($str));
}
}
}
}
}
function add_user($client)
{
$this->sockets[] = $client;
}
function get_message($client)
{
$buf = '';
$len = 0;
$buffer = '';
do{
$l = socket_recv($client, $buf, 1000, 0);
$len += $l;
$buffer .= $buf;
}while($l == 1000);
return $this->decode($buffer);
}
function handshake($client)
{
$len = 0;
$buffer = '';
do{
$l = socket_recv($client, $buf, 1000, 0);
$len += $l;
$buffer .= $buf;
}
while($l == 1000);
//handshake
$buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
$key = trim(substr($buf,0,strpos($buf,"\r\n")));
$new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
$new_message = "HTTP/1.1 101 Switching Protocols\r\n";
$new_message .= "Upgrade: websocket\r\n";
$new_message .= "Sec-WebSocket-Version: 13\r\n";
$new_message .= "Connection: Upgrade\r\n";
$new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
socket_write($client, $new_message, strlen($new_message));
return true;
//handshake over
}
function decode($str){
$mask = array();
$data = '';
$msg = unpack('H*', $str);
$head = substr($msg[1], 0, 2);
if ($head == '81')
{
$len = substr($msg[1], 2, 2);
$len = hexdec($len);
if(substr($msg[1], 2, 2) == 'fe')
{
$len = substr($msg[1], 4, 4);
$len = hexdec($len);
$msg[1] = substr($msg[1],4);
}
else if(substr($msg[1], 2, 2) == 'ff'){
$len = substr($msg[1], 4, 16);
$len = hexdec($len);
$msg[1] = substr($msg[1], 16);
}
$mask[] = hexdec(substr($msg[1], 4, 2));
$mask[] = hexdec(substr($msg[1], 6, 2));
$mask[] = hexdec(substr($msg[1], 8, 2));
$mask[] = hexdec(substr($msg[1], 10, 2));
$s = 12;
$n = 0;
}
else
{
return '';
}
$e = strlen($msg[1]) - 2;
for ($i = $s; $i <= $e; $i += 2)
{
$data .= chr($mask[$n%4]^hexdec(substr($msg[1], $i, 2)));
$n ++;
}
return $data;
}
function code($msg){
$frame = array();
$frame[0] = '81';
$len = strlen($msg);
if($len < 126){
$frame[1] = $len<16?'0'.dechex($len):dechex($len);
}else if($len < 65025){
$s=dechex($len);
$frame[1]='7e'.str_repeat('0',4-strlen($s)).$s;
}else{
$s=dechex($len);
$frame[1]='7f'.str_repeat('0',16-strlen($s)).$s;
}
$frame[2] = $this->ord_hex($msg);
$data = implode('',$frame);
return pack("H*", $data);
}
function ord_hex($data) {
$msg = '';
$l = strlen($data);
for ($i= 0; $i<$l; $i++) {
$msg .= dechex(ord($data{$i}));
}
return $msg;
}
}
?>