websocket 類也是在網上找到的。 修改後能夠用來建立多房間聊天室。能夠發送圖片表情,圖片,及文字。javascript
分享的代碼,已經測試。可正常運行php
HTML 端代碼css
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/> <title>直播課程</title> <link rel="stylesheet" href="css/base.css"> <link rel="stylesheet" href="css/zhibo.css"> <script type="text/javascript" src="js/jquery-1.11.3.min.js"></script> </head> <body class="scope"> <div style="width: 100%; height:250px;"> <script type="text/javascript" src="player/sewise.player.min.js"></script> <script type="text/javascript"> var videourl='視屏播放地址不用寫'; SewisePlayer.setup({ server: "vod", type: "m3u8", autostart: "true", videourl: videourl, skin: "vodWhite", title: "三年級預備課程一", claritybutton: "disable", lang: "zh_CN" }); </script> </div> <div class="log comment" id="log"> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">我是用戶1我是用是用戶1我是用戶1我是用戶1我是用戶1</span></div> </div> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">莫寒</span>:<span class="yuanwang"><img class="chat_pic" src="img/pic.jpg" alt=""></span></div> </div> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">我是用戶1我是用是用戶1我是用戶1我是用戶1我是用戶1</span></div> </div> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">我是用戶1我是用是用戶1我是用戶1我是用戶1我是用戶1</span></div> </div> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">莫寒</span>:<span class="yuanwang"><img class="chat_pic" src="img/150599173575244039.jpg" alt=""></span></div> </div> <div class="luck"> <div class="user"><img src="img/user.png"></div> <div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">我是用戶1我是用是用戶1我是用戶1我是用戶1我是用戶1</span></div> </div> </div> <div class="sendCon"> <p class="info"> <span class="emoji"> <input type="button" value=":)"></span> <span class="placeholder"><img src="img/pic.jpg" alt=""><input type="file" id="file_img" onchange="preImg(this.id,'yulan_img')"></span> <span class="text"><input type="text" id="text" placeholder=""></span> <span class="send"><input type="button" class="btn" value="發送" onclick="sendText()"></span> </p> <ul class="emojiCon"></ul> </div> <script> var serverUrl="http://192.168.3.240"; //圖片服務器的地址ip var url="ws://你自已訪問的ip:端口(8000)"; function link(){ socket=new WebSocket(url); socket.onopen=function(){ // alert('鏈接成功') }; socket.onerror=function(errorEvent){ // alert('error'); } socket.onmessage=function(msg){ setMsg(msg.data); console.log(msg); } // socket.onclose=function(){setMsg('斷開鏈接')} } function closeScoket(){ socket.close(); socket=null; } //向頁面中實時更新消息數據 function setMsg(var1){ var obj=JSON.parse(var1); if(obj.type==1){ $('.log').append('<div class="luck">' +'<div class="user"><img src="img/user.png"></div>' +'<div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">'+obj.msg+'</span></div></div>' ); add(); }else{ var img = new Image(); img.src=obj.msg; img.onload=function(){ var isPic=''; //width>30 表示不是表情包圖片 if(img.width>30){ isPic='<img class="chat_pic" src="'+obj.msg+'" alt="">'; }else{ isPic='<img class="chat_pic1" src="'+obj.msg+'" alt="">' } $('.log').append('<div class="luck">' +'<div class="user"><img src="img/user.png"></div>' +'<div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">'+isPic+'</span></div></div>' ); add(); } } } var arr=[1,2,3,4]; //發送文字 function sendText(id){ var json; if($('#'+id).attr('src')==undefined){ json=JSON.stringify({'room':arr[1],'type':'1','msg':$('#text').val()}); if($('#text').val()==""){ $('body').append(pop("消息不能爲空")); return; } }else{ json=JSON.stringify({'room':arr[1],'type':'2','msg':$('#'+id).attr('src')}); $('.emojiCon').css('display','none'); } socket.send(json); $('#text').val(''); } //發送圖片 function sendPic(){ $.ajax({ url:''+serverUrl+'/test/Home/index/base64_decode', type:'post', data:{'msg':$('#yulan_img').attr('src')}, dataType:'html', success:function(data){ console.log(data); var json=JSON.stringify({'room':arr[3],'type':'2','msg':data}); socket.send(json); $('.mask').remove(); }, error:function(event){ $('body').append(pop('服務器開小差啦~')) } }) } //讓討論區的滾動條始終在底部 讓用戶立馬看到本身的消息 function add(){ var div = document.getElementById('log'); div.scrollTop = div.scrollHeight; } //加載表情包 function afterLoad(){ var html=''; for(var i=0;i<91;i++){ html+='<li><img id="emoji_'+(i+1)+'" onclick="sendText(id)" src="'+serverUrl+'/test/Public/img/qq/'+(i+1)+'.gif" alt=""></li>'; } $('.emojiCon').html(html); } //圖片預覽 function preImg(sourceId, targetId) { if (typeof FileReader === 'undefined') { alert('Your browser does not support FileReader...'); return; } var reader = new FileReader(); reader.onload = function(e) { var img = document.getElementById(targetId); img.src = this.result; var w=img.width; var h=img.height; var winW=$(window).width(); var winH=$(window).height(); var marginTop=parseInt((winH-40-h)/2); var marginLeft=parseInt((winW-w )/2); if(w/h>1.2){ $(img).css('width',winW).css('margin-top',marginTop); alert("marginTop:"+marginTop); }else if(h/w>2){//超長圖的時候 滾動條顯示 $('.over_pic').css('height',winH-40).css('overflow','scroll'); $(img).css('width',winW); }else{//豎圖的時候 $(img).css('height',winH-40).css('margin-left',marginLeft); alert("marginLeft:"+marginLeft); } } reader.readAsDataURL(document.getElementById(sourceId).files[0]); $('body').append('<div class="mask scope"><div class="over_pic"><img id="yulan_img" src="" alt=""></div>' +'<p><button class="sure" onclick="sendPic()">確認</button></p></div>'); } $(function(){ link(); afterLoad(); add(); $('.log').css('height',$(window).height()*0.65+'px'); $('.emoji').click(function(){ $('.emojiCon').show(); }) }) </script> </body> </html>
CSS 前端代碼 basshtml
@charset "utf-8"; /* 禁用iPhone中Safari的字號自動調整 */ html { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family:"微軟雅黑",Arial,sans-serif; } /* 去除iPhone中默認的input樣式 */ input{/* -webkit-appearance:none; */ resize: none;} /* 取消連接高亮 */ body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd,a,img,button,form,table,th,tr,td,tbody,article, aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section{ -webkit-tap-highlight-color:rgba(0, 0, 0, 0); } /* 設置HTML5元素爲塊 */ article, aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section { display: block; } /* 圖片自適應 */ img {width: 100%;height: auto;width:auto\9; /* ie8 */ -ms-interpolation-mode:bicubic;/*爲了照顧ie圖片縮放失真*/} *:focus {outline:none;} /* 清零 */ body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd, a,img,button,form,table,th,tr,td,tbody,article, aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section { margin:0; padding:0; border:none; } em,i{font-style:normal;} strong{font-weight: normal;} .clearfix:after{content:""; display:block; visibility:hidden; height:0; clear:both;} .clearfix{zoom:1;} a{text-decoration:none; color:#969696;} a:hover{ text-decoration:none;} ul,ol,li{list-style:none;} fieldset,img{border: none;} q:before,q:after {content:"";} input:password {ime-mode:disabled;} *{box-sizing:border-box;} .scope{min-width:320px; max-width:750px; margin: 0 auto;} *{ margin: 0; padding: 0; } @media screen and (max-width: 750px){ html{font-size:30px;} } @media screen and (min-width:640px) and (max-width:749px){ html{font-size:25px; } } @media screen and (min-width:480px) and (max-width:639px){ html{font-size:20px; } } @media screen and (min-width:320px) and (max-width:479px){ html{font-size:15px; } } /*body{font-size:62.5%;}*/ fieldset,img{border:0} a{text-decoration:none;color:#000;outline:none} li{list-style:none} h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal} input,button,textarea,select,optgroup,option{ font-family:inherit;font-size:inherit; font-style:inherit;font-weight:inherit} input,button,textarea,select{*font-size:100%} .clear:after{ display:block; content:"clear"; height:0; clear:both; visibility:hidden; } .clear{zoom:1;}
CSS 前端代碼 zhibo前端
.comment{ overflow: scroll; border:1px solid red; padding:2%; } .luck{ padding: 10px 0 0 0; overflow:hidden; } .luckyP{ color:#44c6dd; } .chat_pic{ width:40%; display:inline-block; vertical-align: top; } .chat_pic1{ width:10%; vertical-align: middle; } .user img{ width:40%; } .user,.content1{ float:left; } .user{ width:15%; text-align: center; vertical-align: middle; } .content1{ width:85%; line-height:25px; } .sendCon{ position:fixed; bottom:0; left:0; right:0; padding:2%; background:#fff; border:1px solid #ddd; min-width:320px; max-width:750px; margin:0 auto; } .info span{ display:inline-block; } .placeholder{ width:15%; position:relative; text-align: center; vertical-align: middle; } input[type="file"]{ width:80%; position:absolute; left:2%; top:2%; opacity:0; } .placeholder img{ width:65%; } .emoji{ width:10%; text-align: center; /*vertical-align: middle;*/ /*border:1px solid red;*/ } .emoji input{ width:100%; padding:8% 2%; border:1px solid #ddd; background:#fff; } /*.emoji img{ width:80%; border:1px solid blue; vertical-align: middle; }*/ .text{ width:55%; } #text{ width:100%; border:1px solid #ddd; padding:2%; } .send{ width:15%; } .btn{ width:100%; background:#86e2fd; color:#fff; padding:9% 2%; vertical-align: middle; } .mask{ background:rgba(0,0,0,0.9); width:100%; height:100%; position:fixed; left:0; top:0; /*display:none;*/ } .sure{ background:#19ad17; color:#fff; padding:10px; } .mask p{ text-align: right; position:absolute; bottom:0; left:0; right:0; height:40px; vertical-align: middle; } .over_pic img{ display:block; } /*表情包div*/ .emojiCon{ position:absolute; bottom:0; left:0; display:none; background:#fff; } .emojiCon li{ border:1px solid #ddd; float:left; width:8.33%; }
php 服務端代碼 server.phpjava
<?php include 'websocket.class.php'; $config=array( 'address'=>'你自已ip地址', //注意事 項 linux下雲服務器,用ifconfig 查看自已的內網ip 外網訪問的ip 是用寫在html那塊的 'port'=>'8000', 'event'=>'WSevent',//回調函數的函數名 'log'=>true, ); $websocket = new websocket($config); $websocket->run(); function WSevent($type,$event){ global $websocket; if('in'==$type){ $websocket->log('客戶進入id:'.$event['k']); }elseif('out'==$type){ $websocket->log('客戶退出id:'.$event['k']); }elseif('msg'==$type){ $websocket->log($event['k'].'消息:'.$event['msg']); roboot($event['sign'],$event['msg']); } } function roboot($sign,$t){ global $websocket; $msg_arr = json_decode($t,true); foreach($websocket->users as $k =>&$v){ if(empty($v['room'])){ $v['room']=$msg_arr['room']; } if($v['room'] ==$msg_arr['room']){ $websocket->idwrite($k,$t); } } }
php 服務羰代碼 websocket.class.phpjquery
<?php /* 建立類websocket($config); $config結構: $config=array( 'address'=>'192.168.0.200',//綁定地址 'port'=>'8000',//綁定端口 'event'=>'WSevent',//回調函數的函數名 'log'=>true,//命令行顯示記錄 ); 回調函數返回數據格式 function WSevent($type,$event) $type字符串 事件類型有如下三種 in 客戶端進入 out 客戶端斷開 msg 客戶端消息到達 均爲小寫 $event 數組 $event['k']內置用戶列表的userid; $event['sign']客戶標示 $event['msg']收到的消息 $type='msg'時纔有該信息 方法: run()運行 search(標示)遍歷取得該標示的id close(標示)斷開鏈接 write(標示,信息)推送信息 idwrite(id,信息)推送信息 屬性: $users 客戶列表 結構: $users=array( [用戶id]=>array('socket'=>[標示],'hand'=[是否握手-布爾值]), [用戶id]=>arr..... ) */ class websocket{ public $log; public $event; public $signets; public $users; public $master; public function __construct($config){ if (substr(php_sapi_name(), 0, 3) !== 'cli') { die("請經過命令行模式運行!"); } error_reporting(E_ALL); set_time_limit(0); ob_implicit_flush(); $this->event = $config['event']; $this->log = $config['log']; $this->master=$this->WebSocket($config['address'], $config['port']); $this->sockets=array('s'=>$this->master); } function WebSocket($address,$port){ $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($server, $address, $port); socket_listen($server); $this->log('開始監聽: '.$address.' : '.$port); return $server; } function run(){ while(true){ $changes=$this->sockets; @socket_select($changes,$write=NULL,$except=NULL,NULL); foreach($changes as $sign){ if($sign==$this->master){ $client=socket_accept($this->master); $this->sockets[]=$client; $user = array( 'socket'=>$client, 'hand'=>false, ); $this->users[] = $user; $k=$this->search($client); $eventreturn = array('k'=>$k,'sign'=>$sign); $this->eventoutput('in',$eventreturn); }else{ $len=socket_recv($sign,$buffer,2048,0); $k=$this->search($sign); $user=$this->users[$k]; if($len<7){ $this->close($sign); $eventreturn = array('k'=>$k,'sign'=>$sign); $this->eventoutput('out',$eventreturn); continue; } if(!$this->users[$k]['hand']){//沒有握手進行握手 $this->handshake($k,$buffer); }else{ $buffer = $this->uncode($buffer); $eventreturn = array('k'=>$k,'sign'=>$sign,'msg'=>$buffer); $this->eventoutput('msg',$eventreturn); } } } } } function search($sign){//經過標示遍歷獲取id foreach ($this->users as $k=>$v){ if($sign==$v['socket']) return $k; } return false; } function close($sign){//經過標示斷開鏈接 $k=array_search($sign, $this->sockets); socket_close($sign); unset($this->sockets[$k]); unset($this->users[$k]); } function handshake($k,$buffer){ $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($this->users[$k]['socket'],$new_message,strlen($new_message)); $this->users[$k]['hand']=true; return true; } function uncode($str){ $mask = array(); $data = ''; $msg = unpack('H*',$str); $head = substr($msg[1],0,2); if (hexdec($head{1}) === 8) { $data = false; }else if (hexdec($head{1}) === 1){ $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; $e = strlen($msg[1])-2; $n = 0; for ($i=$s; $i<= $e; $i+= 2) { $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2))); $n++; } } return $data; } function code($msg){ $msg = preg_replace(array('/\r$/','/\n$/','/\r\n$/',), '', $msg); $frame = array(); $frame[0] = '81'; $len = strlen($msg); $frame[1] = $len<16?'0'.dechex($len):dechex($len); $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; } function idwrite($id,$t){//經過id推送信息 if(!$this->users[$id]['socket']){return false;}//沒有這個標示 $t=$this->code($t); return socket_write($this->users[$id]['socket'],$t,strlen($t)); } function write($k,$t){//經過標示推送信息 $t=$this->code($t); return socket_write($k,$t,strlen($t)); } function eventoutput($type,$event){//事件回調 call_user_func($this->event,$type,$event); } function log($t){//控制檯輸出 if($this->log){ $t=$t."\r\n"; fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t)); } } }
php 上傳圖片異步處理代碼 linux
$update_path = "Upload/"; $msg = $_POST['msg']; $exe = str_replace('/', '.', strstr(strstr($msg, ';', TRUE), '/')); $exe = $exe == '.jpeg' ? '.jpg' : $exe; $tmp = base64_decode(substr(strstr($msg, ','), 1)); $path = $update_path . md5(time()) . $exe; $res =file_put_contents($path, $tmp); echo "http://".$_SERVER['SERVER_NAME']."/test/".$path;
window 下 打開dos 命令 找到php.exe 文件位置。用php.exe 執行 server.php 文件開啓服務器監聽。 php.exe server.phpweb
打開html頁面,點擊連接,就能夠連接websocket了。提示成功,即可以發送信息了。ajax
注意事項目:linux 下 濫聽端口時,注意服務器防火牆是否開啓端口過濾。 Linux 有iptables firewall 兩個防火牆軟件件