当前位置:   article > 正文

socket 发送数据 瓶颈_socket编程之websocket实现

qwebsocket通信瓶颈

700456ca5ec4cfcb88a9efd3ae7621f4.png

实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket。

websocket是一种可以双向通讯的长连接协议,http是获取完数据就关闭,websocket则可以一直连接,就像铺了一条管道一样,水可以一直流着。

一、websocket前端

  1. var ws = new WebSocket("ws://127.0.0.1.com:8282");
  2. ws.onopen=function(){
  3. var msg = JSON.stringify({
  4. type: "login",
  5. content: "login"
  6. });
  7. ws.send(msg);
  8. }
  9. ws.onmessage = function (e){
  10. console.log(e);
  11. //服务器发送的内容
  12. var res = JSON.parse(e.data);
  13. switch(res.type){
  14. case "login":
  15. break;
  16. case "pm":
  17. break;
  18. case "groupPm":
  19. break;
  20. }
  21. }
  22. ws.onerror=function (e){
  23. console.log(e);
  24. }
  25. ws.onclose=function (e){
  26. console.log(e);
  27. }

二、服务端

7207899fb0051021b3bfa07965e7f2bf.png


客户端发送http请求,带上Sec-WebSocket-Key,
服务端握手 加密key,发送给客户端。
双方能进行交流。

发送接收消息需要进行打包encode 解包decode。

  1. <?php
  2. class SocketService
  3. {
  4. public $host="tcp://0.0.0.0:8000";
  5. private $address;
  6. private $port;
  7. private $_sockets;
  8. public $clients;
  9. public $maxid=1000;
  10. public function __construct($address = '', $port='')
  11. {
  12. if(!empty($address)){
  13. $this->address = $address;
  14. }
  15. if(!empty($port)) {
  16. $this->port = $port;
  17. }
  18. }
  19. public function onConnect($client_id){
  20. echo "Client client_id:{$client_id} n";
  21. }
  22. public function onMessage($client_id,$msg){
  23. //发给所有的
  24. foreach($this->clients as $kk=>$cc){
  25. if($kk>0){
  26. $this->send($cc, $msg);
  27. }
  28. }
  29. }
  30. public function onClose($client_id){
  31. echo "$client_id close n";
  32. }
  33. public function service(){
  34. //获取tcp协议号码。
  35. $tcp = getprotobyname("tcp");
  36. $sock = stream_socket_server($this->host, $errno, $errstr);;
  37. if(!$sock)
  38. {
  39. throw new Exception("failed to create socket: ".socket_strerror($sock)."n");
  40. }
  41. stream_set_blocking($sock,0);
  42. $this->_sockets = $sock;
  43. echo "listen on $this->address $this->host ... n";
  44. }
  45. public function run(){
  46. $this->service();
  47. $this->clients[] = $this->_sockets;
  48. while (true){
  49. $changes = $this->clients;
  50. //$write = NULL;
  51. //$except = NULL;
  52. stream_select($changes, $write, $except, NULL);
  53. foreach ($changes as $key => $_sock){
  54. if($this->_sockets == $_sock){ //判断是不是新接入的socket
  55. if(($newClient = stream_socket_accept($_sock)) === false){
  56. unset($this->clients[$key]);
  57. continue;
  58. }
  59. $line = trim(stream_socket_recvfrom($newClient, 1024));
  60. //握手
  61. $this->handshaking($newClient, $line);
  62. $this->maxid++;
  63. $this->clients[$this->maxid] = $newClient;
  64. $this->onConnect($this->maxid);
  65. } else {
  66. $res=@stream_socket_recvfrom($_sock, 2048);
  67. //客户端主动关闭
  68. if(strlen($res) < 9) {
  69. stream_socket_shutdown($this->clients[$key],STREAM_SHUT_RDWR);
  70. unset($this->clients[$key]);
  71. $this->onClose($key);
  72. }else{
  73. //解密
  74. $msg = $this->decode($res);
  75. $this->onMessage($key,$msg);
  76. }
  77. }
  78. }
  79. }
  80. }
  81. /**
  82. * 握手处理
  83. * @param $newClient socket
  84. * @return int 接收到的信息
  85. */
  86. public function handshaking($newClient, $line){
  87. $headers = array();
  88. $lines = preg_split("/rn/", $line);
  89. foreach($lines as $line)
  90. {
  91. $line = chop($line);
  92. if(preg_match('/A(S+): (.*)z/', $line, $matches))
  93. {
  94. $headers[$matches[1]] = $matches[2];
  95. }
  96. }
  97. $secKey = $headers['Sec-WebSocket-Key'];
  98. $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
  99. $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshakern" .
  100. "Upgrade: websocketrn" .
  101. "Connection: Upgradern" .
  102. "WebSocket-Origin: $this->addressrn" .
  103. "WebSocket-Location: ws://$this->address:$this->port/websocket/websocketrn".
  104. "Sec-WebSocket-Accept:$secAcceptrnrn";
  105. return stream_socket_sendto($newClient, $upgrade);
  106. }
  107. /**
  108. * 发送数据
  109. * @param $newClinet 新接入的socket
  110. * @param $msg 要发送的数据
  111. * @return int|string
  112. */
  113. public function send($newClinet, $msg){
  114. $msg = $this->encode($msg);
  115. stream_socket_sendto($newClinet, $msg);
  116. }
  117. /**
  118. * 解析接收数据
  119. * @param $buffer
  120. * @return null|string
  121. */
  122. public function decode($buffer){
  123. $len = $masks = $data = $decoded = null;
  124. $len = ord($buffer[1]) & 127;
  125. if ($len === 126) {
  126. $masks = substr($buffer, 4, 4);
  127. $data = substr($buffer, 8);
  128. } else if ($len === 127) {
  129. $masks = substr($buffer, 10, 4);
  130. $data = substr($buffer, 14);
  131. } else {
  132. $masks = substr($buffer, 2, 4);
  133. $data = substr($buffer, 6);
  134. }
  135. for ($index = 0; $index < strlen($data); $index++) {
  136. $decoded .= $data[$index] ^ $masks[$index % 4];
  137. }
  138. return $decoded;
  139. }
  140. /**
  141. *打包消息
  142. **/
  143. public function encode($buffer) {
  144. $first_byte="x81";
  145. $len=strlen($buffer);
  146. if ($len <= 125) {
  147. $encode_buffer = $first_byte . chr($len) . $buffer;
  148. } else {
  149. if ($len <= 65535) {
  150. $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
  151. } else {
  152. $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
  153. }
  154. }
  155. return $encode_buffer;
  156. }
  157. /**
  158. * 关闭socket
  159. */
  160. public function close(){
  161. return socket_close($this->_sockets);
  162. }
  163. }
  164. $sock = new SocketService('127.0.0.1','9000');
  165. $sock->run();

三、常见应用

1.聊天室、群聊 实现类似QQ群的web版本

http://2.im私聊、客服 实现类似qq聊天,和即时客服交流

3.消息推送 建立即时的web消息推送

以上内容希望帮助到大家,需要更多文章可以关注公众号:PHP从入门到精通,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些PHP高级、架构视频资料和大厂PHP面试PDF免费获取,需要戳这里PHP进阶架构师>>>实战视频、大厂面试文档免费获取

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/884107
推荐阅读
相关标签
  

闽ICP备14008679号