您当前位于: 首页 » web前端编程, 互联网2.0, 网络通信协议 » 弄了个websocket 聊天室玩玩

弄了个websocket 聊天室玩玩05/09/2010

今天,我写了个websocket的聊天室demo,实践之后感觉这个东西实现的长连接着实很有诱惑力,在数据量的传输上,除了第一次的handshake,其余的每次传输只在原数据头尾分别加上”\x00″和”\xFF”两个字符(除此之外,和socket便没有任何差别),这个和ajax的传输不太一样,后者属于http协议,因此每次都会带有的头信息。

websocket的协议颇为简单,在第一次handshake通过以后,便建立连接,其后的通讯数据都是以”\x00″开头,以”\xFF”结尾。在客户端,这个是透明的,websocket组件会自动将原始数据“掐头去尾”。

好吧!看看我写的简陋的demo吧(PS:请使用chrome 4.0以上版本来打开页面):
https://www.zendstudio.net/libs/websocket/chat/demo1.html

| 14条评论 标签:  

14条评论
  1. jay说道:

    不错,能把服务端程序也发出来看看么?

  2. 代码狂人说道:

    master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die(“socket_create() failed”);
    socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die(“socket_option() failed”);
    socket_bind($this->master, $address, $port) or die(“socket_bind() failed”);
    socket_listen($this->master,20) or die(“socket_listen() failed”);
    $this->sockets[] = $this->master;
    $this->say(“Server Started : “.date(‘Y-m-d H:i:s’));
    $this->say(“Listening on : “.$address.” port “.$port);
    $this->say(“Master socket : “.$this->master.”\n”);

    while(true){
    $changed = $this->sockets;
    socket_select($changed,$write=NULL,$except=NULL,NULL);
    foreach($changed as $socket){
    if($socket==$this->master){
    $client=socket_accept($this->master);
    if($clientlog(“socket_accept() failed”); continue; }
    else{ $this->connect($client); }
    }
    else{
    $bytes = @socket_recv($socket,$buffer,2048,0);
    if($bytes==0){ $this->disconnect($socket); }
    else{
    $user = $this->getuserbysocket($socket);
    if(!$user->handshake){ $this->dohandshake($user,$buffer); }
    else{ $this->process($user,$this->unwrap($buffer)); }
    }
    }
    }
    }
    }

    function process($user,$msg){
    /* Extend and modify this method to suit your needs */
    /* Basic usage is to echo incoming messages back to client */
    $this->send($user->socket,$msg);
    }

    function send($client,$msg){
    $this->say(“> “.$msg);
    $msg = $this->wrap($msg);
    socket_write($client,$msg,strlen($msg));
    }

    function connect($socket){
    $user = new User();
    $user->id = uniqid();
    $user->socket = $socket;
    array_push($this->users,$user);
    array_push($this->sockets,$socket);
    $this->log($socket.” CONNECTED!”);
    }

    function disconnect($socket){
    $found=null;
    $n=count($this->users);
    for($i=0;$iusers[$i]->socket==$socket){ $found=$i; break; }
    }
    if(!is_null($found)){ array_splice($this->users,$found,1); }
    $index=array_search($socket,$this->sockets);
    socket_close($socket);
    $this->log($socket.” DISCONNECTED!”);
    if($index>=0){ array_splice($this->sockets,$index,1); }
    }

    function dohandshake($user,$buffer){
    $this->log(“\nRequesting handshake…”);
    $this->log($buffer);
    list($resource,$host,$origin) = $this->getheaders($buffer);
    $this->log(“Handshaking…”);
    $upgrade = “HTTP/1.1 101 Web Socket Protocol Handshake\r\n” .
    “Upgrade: WebSocket\r\n” .
    “Connection: Upgrade\r\n” .
    “WebSocket-Origin: ” . $origin . “\r\n” .
    “WebSocket-Location: ws://” . $host . $resource . “\r\n” .
    “\r\n”;
    socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0)));
    $user->handshake=true;
    $this->log($upgrade);
    $this->log(“Done handshaking…”);
    return true;
    }

    function getheaders($req){
    $r=$h=$o=null;
    if(preg_match(“/GET (.*) HTTP/” ,$req,$match)){ $r=$match[1]; }
    if(preg_match(“/Host: (.*)\r\n/” ,$req,$match)){ $h=$match[1]; }
    if(preg_match(“/Origin: (.*)\r\n/”,$req,$match)){ $o=$match[1]; }
    return array($r,$h,$o);
    }

    function getuserbysocket($socket){
    $found=null;
    foreach($this->users as $user){
    if($user->socket==$socket){ $found=$user; break; }
    }
    return $found;
    }

    function say($msg=””){ echo $msg.”\n”; }
    function log($msg=””){ if($this->debug){ echo $msg.”\n”; } }
    function wrap($msg=””){ return chr(0).$msg.chr(255); }
    function unwrap($msg=””){ return substr($msg,1,strlen($msg)-2); }
    function findUser($id){
    foreach($this->users as $u){
    if($u->id==$id)
    return $u;
    }
    return false;
    }

    }

    class User{
    var $id;
    var $socket;
    var $handshake;
    }

    ?>

  3. woyiwuqing说道:

    友情提示:请使用chorme 4.0以上版本来打开页面 这里你将谷歌浏览器的名称打错了,是chrome…

  4. HTML5爱好说道:

    楼主共享下噻或发我邮箱…以后HTML5正式出来了.这种代码多了.为国家HTML5发展做点贡献嘛。
    现在HTML5 SOCKET的学习资料太少了。

    • gently说道:

      我的另一篇文章已经详细的介绍了web socket 协议,这为国家作出的巨大贡献岂是尔等张口就能衡量的

  5. HTML5爱好说道:

    476850@qq.com

  6. conall说道:

    PPC 围观团求代码!

    zyc1991#gmail.com

  7. stefan说道:

    gently,我现在自己在开发一个基于html5 canvas和websocket的动态聊天室,界面是星球大战的形式。我现在遇到个问题,因为我想把它放到虚拟空间里。但是空间只开放80和ftp。我想让websocket和普通的HTTP请求复用80端口,如何解决。现在的情况是,我开了websocket的server,其他80请求都会死掉。有什么办法能让两者共存?

  8. help说道:

    为什么我看到的效果是自动断开连接

  9. 琼台老屋说道:

    强!!!找了好久了

发表评论