加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSS
您当前的位置:首页 > 学习资料

PHP 简单实现webSocket

时间:2021-03-21 23:33:46  来源:  作者:
1)客户端实现
  1. <html>
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>Web sockets test</title>
  5. <script src="jquery-min.js" type="text/javascript"></script>
  6. <script type="text/javascript">
  7. var ws;
  8. function ToggleConnectionClicked() {         
  9. try {
  10. ws = new WebSocket("ws://127.0.0.1:2000");//连接服务器        
  11. ws.onopen = function(event){alert("已经与服务器建立了连接\r\n当前连接状态:"+this.readyState);};
  12. ws.onmessage = function(event){alert("接收到服务器发送的数据:\r\n"+event.data);};
  13. ws.onclose = function(event){alert("已经与服务器断开连接\r\n当前连接状态:"+this.readyState);};
  14. ws.onerror = function(event){alert("WebSocket异常!");};
  15. } catch (ex) {
  16. alert(ex.message);      
  17. }
  18. };
  19.  
  20. function SendData() {
  21. try{
  22. var content = document.getElementById("content").value;
  23. if(content){
  24. ws.send(content);
  25. }
  26.  
  27. }catch(ex){
  28. alert(ex.message);
  29. }
  30. };
  31.  
  32. function seestate(){
  33. alert(ws.readyState);
  34. }
  35.  
  36. </script>
  37. </head>
  38. <body>
  39. <button id='ToggleConnection' type="button" onclick='ToggleConnectionClicked();'>连接服务器</button><br /><br />
  40. <textarea id="content" ></textarea>
  41. <button id='ToggleConnection' type="button" onclick='SendData();'>发送我的名字:beston</button><br /><br />
  42. <button id='ToggleConnection' type="button" onclick='seestate();'>查看状态</button><br /><br />
  43.  
  44. </body>
  45. </html>
  46.  
复制代码


2)服务器端实现

 
  1. class WS {
  2. var $master;  // 连接 server 的 client
  3. var $sockets = array(); // 不同状态的 socket 管理
  4. var $handshake = false; // 判断是否握手
  5.  
  6. function __construct($address, $port){
  7. // 建立一个 socket 套接字
  8. $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)   
  9. or die("socket_create() failed");
  10. socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1)  
  11. or die("socket_option() failed");
  12. socket_bind($this->master, $address, $port)                    
  13. or die("socket_bind() failed");
  14. socket_listen($this->master, 2)                              
  15. or die("socket_listen() failed");
  16.  
  17. $this->sockets[] = $this->master;
  18.  
  19. // debug
  20. echo("Master socket  : ".$this->master."\n");
  21.  
  22. while(true) {
  23. //自动选择来消息的 socket 如果是握手 自动选择主机
  24. $write = NULL;
  25. $except = NULL;
  26. socket_select($this->sockets, $write, $except, NULL);
  27.  
  28. foreach ($this->sockets as $socket) {
  29. //连接主机的 client
  30. if ($socket == $this->master){
  31. $client = socket_accept($this->master);
  32. if ($client < 0) {
  33. // debug
  34. echo "socket_accept() failed";
  35. continue;
  36. } else {
  37. //connect($client);
  38. array_push($this->sockets, $client);
  39. echo "connect client\n";
  40. }
  41. } else {
  42. $bytes = @socket_recv($socket,$buffer,2048,0);
  43. print_r($buffer);
  44. if($bytes == 0) return;
  45. if (!$this->handshake) {
  46. // 如果没有握手,先握手回应
  47. $this->doHandShake($socket, $buffer);
  48. echo "shakeHands\n";
  49. } else {
  50.  
  51. // 如果已经握手,直接接受数据,并处理
  52. $buffer = $this->decode($buffer);
  53. //process($socket, $buffer);
  54. echo "send file\n";
  55. }
  56. }
  57. }
  58. }
  59. }
  60.  
  61. function dohandshake($socket, $req)
  62. {
  63. // 获取加密key
  64. $acceptKey = $this->encry($req);
  65. $upgrade = "HTTP/1.1 101 Switching Protocols\r\n" .
  66. "Upgrade: websocket\r\n" .
  67. "Connection: Upgrade\r\n" .
  68. "Sec-WebSocket-Accept: " . $acceptKey . "\r\n" .
  69. "\r\n";
  70.  
  71. echo "dohandshake ".$upgrade.chr(0);           
  72. // 写入socket
  73. socket_write($socket,$upgrade.chr(0), strlen($upgrade.chr(0)));
  74. // 标记握手已经成功,下次接受数据采用数据帧格式
  75. $this->handshake = true;
  76. }
  77.  
  78.  
  79. function encry($req)
  80. {
  81. $key = $this->getKey($req);
  82. $mask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  83.  
  84. return base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
  85. }
  86.  
  87. function getKey($req)
  88. {
  89. $key = null;
  90. if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) {
  91. $key = $match[1];
  92. }
  93. return $key;
  94. }
  95.  
  96. // 解析数据帧
  97. function decode($buffer)  
  98. {
  99. $len = $masks = $data = $decoded = null;
  100. $len = ord($buffer[1]) & 127;
  101.  
  102. if ($len === 126)  {
  103. $masks = substr($buffer, 4, 4);
  104. $data = substr($buffer, 8);
  105. } else if ($len === 127)  {
  106. $masks = substr($buffer, 10, 4);
  107. $data = substr($buffer, 14);
  108. } else  {
  109. $masks = substr($buffer, 2, 4);
  110. $data = substr($buffer, 6);
  111. }
  112. for ($index = 0; $index < strlen($data); $index++) {
  113. $decoded .= $data[$index] ^ $masks[$index % 4];
  114. }
  115. return $decoded;
  116. }
  117.  
  118. // 返回帧信息处理
  119. function frame($s)
  120. {
  121. $a = str_split($s, 125);
  122. if (count($a) == 1) {
  123. return "\x81" . chr(strlen($a[0])) . $a[0];
  124. }
  125. $ns = "";
  126. foreach ($a as $o) {
  127. $ns .= "\x81" . chr(strlen($o)) . $o;
  128. }
  129. return $ns;
  130. }
  131.  
  132. // 返回数据
  133. function send($client, $msg)
  134. {
  135. $msg = $this->frame($msg);
  136. socket_write($client, $msg, strlen($msg));
  137. }
  138. }
  139.  
  140.    测试    $ws = new WS("127.0.0.1",2000);
  141.  
  142.  
复制代码

 
 
 
 
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
推荐资讯
实现php间隔一段时间执行一次某段代码
实现php间隔一段时间
相关文章
    无相关信息
栏目更新
栏目热门