找了一些websocket的资料,但是无论是使用他们提供的代码还是我自己写的代码,在客户端连接的时候都显示403错误、、
我用的是 apache2.4 x64 for windows + php
代码应该是没错的。。。
然后在浏览器中打开 server.php
在另一个窗口中使用 var ws = new WebSocket("ws://path:port")
返回的错误为
Error during WebSocket handshake: Unexpected response code: 403
求解。。。
1
feiyuanqiu 2015-05-08 04:34:05 +08:00
websocket 需要先握手建立连接之后才能通信,你握手那里是怎么处理的呢
server.php 只是一个验证性的 demo 吧? 如果不长,可以发出来看看 |
2
ericls 2015-05-08 04:57:26 +08:00
看看服务器那边的日志呢?
|
3
flowfire OP @feiyuanqiu
代码。。。。我一开始就是嫌太长了所以没发。。。。 <?php set_time_limit(0); class ws{ public $sock; public $socks; public $users; function send($socket,$msg){ if($socket==="all"){ foreach ($this->user as $key => $value) { socket_write($this->user[$key]['client'],$msg,strlen($msg)); } } socket_write($socket,$msg,strlen($msg)); } function handshake($socket,$data){ $secretkey = substr($buffer,strpos($data,'Sec-WebSocket-Key:')+18); $skey = trim(substr($secretkey,0,strpos($secretkey,"\r\n"))); $newskey = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));//生成返回的握手包key,后面的字符串是固定的,不知道谁规定的。。。 $httpheader = "HTTP/1.1 101 Switching Protocols\r\n"; $httpheader .= "Upgrade: websocket\r\n"; $httpheader .= "Connection: Upgrade\r\n"; $httpheader .= "Sec-WebSocket-Accept: ".$newskey."\r\n\r\n"; send($socket,$httpheader); $key = search($socket); $this->users[($key-1)]["new"]=false; return true; } function search($socket){ foreach ($this->socks as $key => $value) { if($socket===$value) return $key; } } function close($socket){ socket_close($socket); $key = search($socket); unset($this->socks[$key]); if($key!==0) unset($this->user[($key-1)]); return true; } function __construct($ip,$port){ $this->sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); socket_bind($this->sock,$ip,$port); socket_listen($this->sock); $this->socks[] = $this->sock; while(1){ $sockscache = $this->socks; socket_select($sockscache,$write = null,$expect =null,null); foreach($sockscache as $sockcache){ if($sockcache === $this->sock){ $client = socket_accept($this->sock); $this->socks[] = $client; $this->users[] = array("client"=>$client,"name"=>"","new"=>true); }else{ $length = socket_recv($sockcache,$data,2048,0); $key = search($sockcache); if($length<7){ $name = $this->users[($key-1)]["name"]; send($sockcache,"$name 已经退出。"); close($sockcache); }else{ if($this->user[($key-1)]["new"]){ handshake($sockcache,$data); }else{ //信息处理 echo $data; die(); } } } } } } } $websocket = new ws("127.0.0.1","1077"); |
4
feiyuanqiu 2015-05-08 16:44:13 +08:00 1
嗯调了一下,怎么说呢,这个代码里面有很多小问题,比如:
1、类方法调用没有用 this 2、$this->user,$this->users 混乱 3、handshake 方法里面的变量 $buffer 没有声明赋值,实际上它应该是参数 $data 4、handshake 方法里面的 $skey 变量在后面的调用中写错了 ... 后面的我都没记录了,都是小问题,改了就能运行了: 附上代码 服务端: <?php error_reporting(E_ERROR); class ws { public $sock; public $socks; public $users; function send($socket, $msg) { if ($socket === "all") { foreach ($this->users as $key => $value) { socket_write($this->users[ $key ]['client'], $msg, strlen($msg)); } } socket_write($socket, $msg, strlen($msg)); } function handshake($socket, $data) { $buffer = $data; $secretkey = substr($buffer, strpos($data, 'Sec-WebSocket-Key:') + 18); $skey = trim(substr($secretkey, 0, strpos($secretkey, "\r\n"))); //生成返回的握手包key,后面的字符串是固定的,不知道谁规定的。。。 $newskey = base64_encode(sha1($skey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", TRUE)); $httpheader = "HTTP/1.1 101 Switching Protocols\r\n"; $httpheader .= "Upgrade: websocket\r\n"; $httpheader .= "Connection: Upgrade\r\n"; $httpheader .= "Sec-WebSocket-Accept: " . $newskey . "\r\n\r\n"; $this->send($socket, $httpheader); $key = $this->search($socket); $this->users[$key-1]["new"] = FALSE; return TRUE; } function search($socket) { return array_search($socket, $this->socks); } function close($socket) { socket_close($socket); $key = $this->search($socket); unset($this->socks[ $key ]); if ($key !== 0) { unset($this->users[$key-1]); } return TRUE; } function decode($buffer) { $decoded = null; $len = ord($buffer[1]) & 127; if ($len === 126) { $masks = substr($buffer, 4, 4); $data = substr($buffer, 8); } else if ($len === 127) { $masks = substr($buffer, 10, 4); $data = substr($buffer, 14); } else { $masks = substr($buffer, 2, 4); $data = substr($buffer, 6); } for ($index = 0; $index < strlen($data); $index++) { $decoded .= $data[$index] ^ $masks[$index % 4]; } return $decoded; } function __construct($ip, $port) { f('start...'); $this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); f('create socket...'); socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1); f('set option...'); socket_bind($this->sock, $ip, $port); f('bind socket...'); socket_listen($this->sock); f('listen socket...'); $this->socks[] = $this->sock; while (1) { $write = NULL; $expect = NULL; $sockscache = $this->socks; if (socket_select($sockscache, $write, $expect, 0) === false) { die("socket_select() failed, reason: " . socket_strerror(socket_last_error()) . "\n"); } foreach ($sockscache as $sockcache) { if ($sockcache === $this->sock) { if (($client = socket_accept($this->sock)) !== false) { f('accept socket...'); $this->socks[] = $client; $this->users[] = array("client" => $client, "name" => "", "new" => TRUE); } } else { $length = socket_recv($sockcache, $data, 2048, 0); f('receive socket...'); $key = $this->search($sockcache); if ($length < 7) { $name = $this->users[$key-1]["name"]; $this->send($sockcache, "$name 已经退出。"); $this->close($sockcache); f('close socket...'); } else { if ($this->users[$key-1]["new"]) { $this->handshake($sockcache, $data); f('handshake...'); } else { //信息处理 $data = $this->decode($data); echo $data; die(); } } } } usleep(500); } } } function f($msg = '') { static $start = false; if (!$start) { ob_start(); $start = true; } echo date('Y-m-d H:i:s') . ":{$msg}\n"; ob_flush(); } $websocket = new ws('127.0.0.1', '10077'); 客户端: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> //<![CDATA[ var ws = new WebSocket('ws://localhost:10077/phpstorm/test2.php'); ws.onopen = function (event) { var data = event.data; console.log('onopen:', data, event); }; ws.onerror = function (event) { var data = event.data; console.log('onerror:', data, event); }; ws.onclose = function (event) { var data = event.data; console.log('onclose:', data, event); }; ws.onmessage = function (event) { var data = event.data; console.log('onmessage:', data, event); }; //]]> </script> </body> </html> |
5
flowfire OP |
6
flowfire OP @feiyuanqiu 但是我用上别人提供的代码也是403错误啊。。。他说已经测试成功了
|
8
flowfire OP @feiyuanqiu 我大概找到原因了。。。。我果然是傻得。。。请求ws连接不能带path。。。。直接ip:portj就好了
|