English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
في الآونة الأخيرة، بينما كنت أقوم ببناء غرفة محادثة مرئية في الشركة، كنت بحاجة إلى استخدام chatsever، لذا قمت بالبحث عن تنفيذ websocket في html5 لتحقيق اتصال ثنائي، وبناءً على تجارب الآخرين، قمت بالتعذيب لعدة أيام وأنا أقوم بإنشاء غرفة دردشة، تمكنت من إرسال الصور، إرسال تعبيرات QQ، دردشة جماعية وسرية، وأود مشاركتها مع جميع المبتدئين للمراجعة والتعلم، يمكن للخبراء تجاهلها.
مقدم:client.html
<!doctype html> <هتمل> <رأس> <متا اسم="charset" محتوى="utf-8"> <متا اسم="viewport" محتوى="عرض=عرض-الجهاز,مقياس-بداية=1,منسق-المستخدم=no"/> <عنوان>HTML5 websocket صفحة دردشة javascript php</عنوان> <style نوع="text/css"> جسم,ب{حاشية:0بكسل; سماكة:0بكسل; حجم:14بكسل; لون:#333; عائلة-خط:Arial, Helvetica, sans-serif;} #ltian,.rin{عرض:98%; حاشية:5بكسل أوتوماتيكية;} #ltian{حافة:1بكسل #ccc صلبة;تدفق-ي:تدفق-أفقية; موقف:نسبي;} #ct{margin-right:111px; height:100%;overflow-y:auto;overflow-x: hidden;} #us{width:110px; overflow-y:auto; overflow-x:hidden; float:right; border-left:1px #ccc solid; height:100%; background-color:#F1F1F1;} #us p{padding:3px 5px; color:#08C; line-height:20px; height:20px; cursor:pointer; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;} #us p:hover,#us p:active,#us p.ck{background-color:#069; color:#FFF;} #us p.my:hover,#us p.my:active,#us p.my{color:#333;background-color:transparent;} button{float:right; width:80px; height:35px; font-size:18px;} input{width:100%; height:30px; padding:2px; line-height:20px; outline:none; border:solid 1px #CCC;} .rin p{margin-right:160px;} .rin span{float:right; padding:6px 5px 0px 5px; position:relative;} .rin span img{margin:0px 3px; cursor:pointer;} .rin span form{position:absolute; width:25px; height:25px; overflow:hidden; opacity:0; top:5px; right:5px;} .rin span input{width:180px; height:25px; margin-left:-160px; cursor:pointer} #ct p{padding:5px; line-height:20px;} #ct a{color:#069; cursor:pointer;} #ct span{color:#999; margin-right:10px;} .c2{color:#999;} .c3{background-color:#DBE9EC; padding:5px;} .qp{position:absolute; font-size:12px; color:#666; top:5px; right:130px; text-decoration:none; color:#069;} #ems{position:absolute; z-index:5; display:none; top:0px; left:0px; max-width:230px; background-color:#F1F1F1; border:solid 1px #CCC; padding:5px;} #ems img{width:44px; height:44px; border:solid 1px #FFF; cursor:pointer;} #ems img:hover,#ems img:active{border-color:#A4B7E3;} #ems a{color:#069; border-radius:2px; display:inline-block; margin:2px 5px; padding:1px 8px; text-decoration:none; background-color:#D5DFFD;} #ems a:hover,#ems a:active,#ems a.ck{color:#FFF; background-color:#069;} .tc{text-align:center; margin-top:5px;} </style> </head> <body> <div id="ltian"> <div id="us" class="jb"></div> <div id="ct"></div> <a href="javascript:;" rel="external nofollow" rel="external nofollow" class="qp" onClick="this.parentNode.children[1].innerHTML=''">إزالة الشاشة</a> </div> <div class="rin"> <button id="sd">إرسال</button> <span><img src="http://www.yxsss.com/ui/sk/t.png" title="[#1#]" id="imgbq"><img src="http://www.yxsss.com/ui/sk/e.png" title="[#2#]"><form><input type="file" title="[#2#]" id="upimg"></form></span> <p><input id="nrong"></p> </div> <div id="ems"><p></p><p class="tc"></p></div> <script> if(typeof(WebSocket)=='undefined'){ alert('لا يدعم متصفحك WebSocket،نوصي باستخدام Google Chrome أو Mozilla Firefox'); } </script> <script src="http://www.yxsss.com/ui/p/a.js" type="text/javascript"></script> <script> (function(){ var key='all',mkey; var users={}; var url='ws://127.0.0.1:8000'; var so=false,n=false; var lus=A.$('us'),lct=A.$('ct'); function st(){ var Arr1 = ["ذكي","خبيث","مضحك","جميل","خبيث","لطيف","جذاب","مضحك"]; var Arr2 = ['الذئب الأبيض','الخروف الأبيض','التمساح الأم','الكائنات الفضائية','بيكا丘','هيلو كيتي','شو يي شين','شيه تشي هون']; var ran1 = Math.floor(Math.random() * Arr1.length + 1)-1; var ran2 = Math.floor(Math.random() * Arr2.length + 1)-1; var n=Arr1[ran1]+Arr2[ran2]; //السطور الخمس أعلاه هي طريقة لإنشاء اسم مستخدم عشوائي، يرجى الرجوع إليها، إذا كنت ترغب في تحديد اسم مستخدم يمكنك تعليق السطور الخمس أعلاه وتفعيل السطور التالية //n=prompt('من فضلك اختر اسمًا قويًا:'); //n=n.substr(0,16); //console.log(n); if(!n){ return ; } so=new WebSocket(url); so.onopen=function(){ if(so.readyState==1){ so.send('type=add&ming='+n); } } so.onclose=function(){ so=false; lct.appendChild(A.$$('<p class="c2">تسجيل الخروج من غرفة الدردشة</p>')); } so.onmessage=function(msg){ eval('var da='+msg.data); var obj=false,c=false; if(da.type=='add'){ var obj=A.$$('<p>'+da.name+'</p>'); lus.appendChild(obj); cuser(obj,da.code); obj=A.$$('<p><span>['+da.time+']</span>مرحبًا <a>'+da.name+'</a> لقد انضممت</p>'); تعريف c=da.code; }else if(da.type=='madd'){ mkey=da.code; da.users.unshift({'code':'all','name':'大家'}); for(var i=0;i<da.users.length;i++){ var obj=A.$$('<p>'+da.users[i].name+'</p>'); lus.appendChild(obj); if(mkey!=da.users[i].code){ cuser(obj,da.users[i].code); } obj.className='my'; document.title=da.users[i].name; } } obj=A.$$('<p><span>['+da.time+']</span>مرحبًا '+da.name+' قد انضم</p>'); users.all.className='ck'; } if(obj==false){ if(da.type=='rmove'){ var obj=A.$$('<p class="c2"><span>['+da.time+']</span>'+users[da.nrong].innerHTML+'يغادر غرفة الدردشة</p>'); lct.appendChild(obj); users[da.nrong].del(); delete users[da.nrong]; } da.nrong=da.nrong.replace(/{\(\d+)}/g,function(a,b){ return '<img src="sk/'+b+'.jpg">'; }).replace(/^data:image/png;base64,.{50,}$/i,function(a){ return '<img src="'+a+'">'; }); //da.code هو code للمرسل if(da.code1==mkey){ obj=A.$$('<p class="c3"><span>['+da.time+']</span><a>'+users[da.code].innerHTML+'</a>يخبرني:'+da.nrong+'</p>'); تعريف c=da.code; }else if(da.code==mkey){ if(da.code1!='all') obj=A.$$('<p class="c3"><span>['+da.time+']</span>أنا أقول ل<a>'+users[da.code1].innerHTML+'</a>:'+da.nrong+'</p>'); else obj=A.$$('<p><span>['+da.time+']</span>أنا أقول ل<a>'+users[da.code1].innerHTML+'</a>:'+da.nrong+'</p>'); تعريف c=da.code1; أو إذا كان da.code==false{ obj=A.$$('<p><span>['+da.time+']</span>'+da.nrong+'</p>'); أو إذا كان da.code1{ obj=A.$$('<p><span>['+da.time+']</span><a>'+users[da.code].innerHTML+'</a>يقول لـ'+users[da.code1].innerHTML+': '+da.nrong+'</p>'); تعريف c=da.code; } } } إذا كان c{ obj.children[1].onclick=function(){ users[c].onclick(); } } lct.appendChild(obj); lct.scrollTop=Math.max(0,lct.scrollHeight-lct.offsetHeight); } } A.$('sd').onclick=function(){ if(!so){ return st(); } تعريف da=A.$('nrong').value.trim(); إذا كان da==''{ تنبيه('المحتوى لا يمكن أن يكون فارغًا'); return false; } A.$('nrong').value=''; so.send('nr='+esc(da)+'&key='+key); } A.$('nrong').onkeydown=function(e){ var e=e||event; إذا كان e.keyCode==13{ A.$('sd').onclick(); } } function esc(da){ da=da.replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"'); تعريف return encodeURIComponent(da); } function cuser(t,code){ users[code]=t; t.onclick=function(){ t.parentNode.children.rcss('ck',''); t.rcss('','ck'); تعريف key=code; } } A.$$('ltian').style.height=(document.documentElement.clientHeight - 70)+'px'; st(); تعريف bq=A.$('imgbq')،ems=A.$('ems'); تعريف l=80،r=4،c=5،s=0،p=Math.ceil(l/(r*c)); var pt='sk/'; bq.onclick=function(e){ var e=e||event; if(!so){ return st(); } ems.style.display='block'; document.onclick=function(){ gb(); } ct(); try{e.stopPropagation();}catch(o){} } for(var i=0;i<p;i++){ var a=A.$$('<a href="javascript:;" rel="external nofollow" rel="external nofollow" >'+(i+1)+'</a>'); ems.children[1].appendChild(a); ef(a,i); } ems.children[1].children[0].className='ck'; function ct(){ var wz=bq.weiz(); with(ems.style){ top=wz.y-242+'px'; left=wz.x+bq.offsetWidth-235+'px'; } } function ef(t,i){ t.onclick=function(e){ var e=e||event; s=i*r*c; ems.children[0].innerHTML=''; hh(); this.parentNode.children.rcss('ck',''); this.rcss('','ck'); try{e.stopPropagation();}catch(o){} } } function hh(){ var z=Math.min(l,s+r*c); for(var i=s;i<z;i++){ var a=A.$$('<img src="'+pt+i+'.jpg">'); hh1(a,i); ems.children[0].appendChild(a); } ct(); } function hh1(t,i){ t.onclick=function(e){ var e=e||event; A.$('nrong').value+='{\\'+i+'}'; if(!e.ctrlKey){ gb(); } try{e.stopPropagation();}catch(o){} } } function gb(){ ems.style.display=''; A.$('nrong').focus(); document.onclick=''; } hh(); A.on(window,'resize',function(){ A.$$('ltian').style.height=(document.documentElement.clientHeight - 70)+'px'; ct(); }) var fimg=A.$$('upimg'); var img=new Image(); var dw=400,dh=300; A.on(fimg,'change',function(ev){ if(!so){ st(); return false; } if(key=='all'){ alert('Due to resource limitations, images can only be sent in private chat'); return false; } var f=ev.target.files[0]; if(f.type.match('image.*')){ var r = new FileReader(); r.onload = function(e){ img.setAttribute('src',e.target.result); }; r.readAsDataURL(f); } }); img.onload=function(){ ih=img.height,iw=img.width; if(iw/ih > dw/dh && iw > dw){ ih=ih/iw*dw; iw=dw; }else if(ih > dh){ iw=iw/ih*dh; ih=dh; } var rc = A.$$('canvas'); var ct = rc.getContext('2d'); rc.width=iw; rc.height=ih; ct.drawImage(img,0,0,iw,ih); var da=rc.toDataURL(); so.send('nr='+esc(da)+'&key='+key); } })(); </script> </body> </html>
backend code: webserver.php
<?php error_reporting(E_ALL ^ E_NOTICE); ob_implicit_flush(); $sk=new Sock('127.0.0.1',8000); $sk->run(); class Sock{ public $sockets; public $users; public $master; private $slen=array()/total length of data private $sjen=array()/length of received data private $ar=array()/key encrypt private $n=array(); public function __construct($address, $port){ $this->master=$this->WebSocket($address, $port); function run(){ $this->sockets=array($this->master); } while(true){ $changes=$this->sockets; $write=NULL; $except=NULL; socket_select($changes,$write,$except,NULL); foreach($changes as $sock){ if($sock==$this->master){ $client=socket_accept($this->master); $key=uniqid(); $this->sockets[]=$client; $this->users[$key]=array( 'socket'=>$client 'shou'=>false ); $len=0; } $buffer=''; do{ $l=socket_recv($sock,$buf,1000,0); $len+=$l; $buffer.=$buf; while($l==1000); } $k=$this->search($sock); if($len<7){ $this->send2($k); continue; } if(!$this->users[$k]['shou']){ $this->woshou($k,$buffer); } $buffer = $this->uncode($buffer,$k); if($buffer==false){ continue; } $this->send($k,$buffer); } } } } } function close($k){ socket_close($this->users[$k]['socket']); unset($this->users[$k]); $this->sockets=array($this->master); foreach($this->users as $v){ $this->sockets[]=$v['socket']; } $this->e("\مفتاح:$k \إغلاق"); } function search($sock){ foreach ($this->users as $k=>$v){ if($sock==$v['socket']) return $k; } return false; } 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->e('\بدء-الخادم: '+date('Y-m-d H:i:s')); $this->e('\استماع-على: '+$address+' \منفذ '+$port); return $server; } function woshou($k,$buffer){ $buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18); $key = trim(substr($buf,0,strpos($buf,"\ر\ن"))); $key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true)); $new_message = "HTTP/1.1 101 \تبديل-المProtocols \ر\ن"; $new_message .= ": \تحسين: websockets \ر\ن"; $new_message .= ": \إصدار-WebSockets: 13 \ر\ن"; $new_message .= ": \فتح \ر\ن"; $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]['shou']=true; return true; } function uncode($str,$key){ $mask = array(); $data = ''; $msg = unpack('H*',$str); $head = substr($msg[1],0,2); if ($head == '81' && !isset($this->slen[$key])) { $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 if($this->slen[$key] > 0){ $len=$this->slen[$key]; $mask=$this->ar[$key]; $n=$this->n[$key]; $s = 0; } $e = strlen($msg[1])-2; for ($i=$s; $i<= $e; $i+= 2) { $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2))); $n++; } $dlen=strlen($data); if($len > 255 && $len > $dlen+intval($this->sjen[$key])){ $this->ar[$key]=$mask; $this->slen[$key]=$len; $this->sjen[$key]=$dlen+intval($this->sjen[$key]); $this->sda[$key]=$this->sda[$key].$data; $this->n[$key]=$n; return false; } unset($this->ar[$key],$this->slen[$key],$this->sjen[$key],$this->n[$key]); $data=$this->sda[$key].$data; unset($this->sda[$key]); 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; } $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; } //المستخدم ينضم function send($k,$msg){ parse_str($msg,$g); $ar=array(); if($g['type']=='add'){ $this->users[$k]['name']=$g['ming']; $ar['type']='add'; $ar['name']=$g['ming']; $key='all'; } $ar['nrong']=$g['nr']; $key=$g['key']; } $this->send1($k,$ar,$key); } function getusers(){ $ar=array(); foreach($this->users as $k=>$v){ $ar[]=array('code'=>$k,'name'=>$v['name']); } return $ar; } //$k رمز المرسل $key رمز المستلم function send1($k,$ar,$key='all'){ $ar['code1']=$key; $ar['code']=$k; $ar['time']=date('m-d H:i:s'); $str = $this->code(json_encode($ar)); if($key=='all'){ $users=$this->users; if($ar['type']=='add'){ $ar['type']='madd'; $ar['users']=$this->getusers(); $str1 = $this->code(json_encode($ar)); socket_write($users[$k]['socket'],$str1,strlen($str1)); unset($users[$k]); } foreach($users as $v){ socket_write($v['socket'],$str,strlen($str)); } } socket_write($this->users[$k]['socket'],$str,strlen($str)); socket_write($this->users[$key]['socket'],$str,strlen($str)); } } //المستخدم يخرج function send2($k){ $this->close($k); $ar['type']='rmove'; $ar['nrong']=$k; $this->send1(false,$ar,'all'); } function e($str){ //$path=dirname(__FILE__).'/log.txt'; $str=$str."\n"; //error_log($str,3,$path); echo iconv('utf-8','gbk//IGNORE',$str); } } ?>
كثير من الأصدقاء قد أعربوا عن استيائهم من مشروع الكود المصدر الخاص بي، حيث يظهر خطأ عند التشغيل ولا يمكن تشغيله، وسأقوم بشرح خطوات التثبيت والتشغيل بشكل مفصل.
أولاً، قم بإخراج ملفات الكود المصدر من التغليف وإضافتها إلى دليل web، على سبيل المثال، في حالتي هو applications/Xampp/xamppfiles/htdocs/phpb/websocket,
المسار
ثم استخدم أداة سطر الأوامر cd للدخول إلى هذا الدليل، وسيتم تشغيل الأمر التالي:
php websocket.php
شكل التشغيل:
عمليات إدخال السطر
ثم قم بفتح خادم Apache، واستخدام المتصفح للوصول إلى http://localhost/phpb/websocket/client.html
شكل التشغيل:
رابط المصدر:webSoket-php-chatsever_jb51.rar
هذا هو نهاية محتوى هذا المقال، آمل أن يكون قد ساعدكم في التعلم، وأتمنى أن تدعموا دليل تعليم النفخة.
بيان: محتويات هذا المقال تم جمعها من الإنترنت، وتعود حقوق الطبع والنشر لمالكها الأصلي، والمحتوى تم إضافته من قبل مستخدمي الإنترنت بشكل تلقائي، ولا يمتلك هذا الموقع حقوق الملكية، ولم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية. إذا كنت قد وجدت محتوى يشتبه في انتهاك حقوق النسخ، فأنت موصى به أن ترسل بريدًا إلكترونيًا إلى notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال '#' بـ '@') لتقديم الشكوى، وتمكنك من تقديم الأدلة، وسيتم حذف المحتوى المزعوم المزعوم على الفور إذا تم التحقق من صحة الشكوى.