php + html5 websocket 【握手篇】
作者:nango
阅读:1425次
来源:原创
时间:2017-01-13 18:06
##### websocket 是什么 WebSocket 是一个独立的基于 TCP 的协议,它与 HTTP 之间的唯一关系就是它的握手请求可以作为一个升级请求(Upgrade request)经由 HTTP 服务器解释(也就是可以使用 Nginx 反向代理一个 WebSocket)。 websocket是HTML5出的新的一种协议,类似于http,只不过它是一种持久链接,而http是一种非持久链接类(短链接)协议,在客户端与服务端握手阶段依然还要靠http。 ##### websocket 和 socket(php) 当然,websocket是一种协议,而socket是php的一个模块,php提供了socket扩展来方便的操作socket。下边就主要是通过HTML5+socket(php)进行握手、通信。 代码如下: ##### tcp/ip 和 http、websocket 首先,tcp/ip是一个协议簇,tcp为传输层协议,ip为网络层协议,而http、websocket为应用层协议;他们直接的关系就引用一个在一篇博文中看到这样的一个比喻: > IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等 当然也包括websocket协议了;那么对于携带的http、websocket协议主要是带给客户端,如浏览器等;浏览器收到原来你让我用http协议来解析此次的数据包,那么我就用http;如果你让我用websocket来解析呢,当然了,我很听话,那就websocket吧。因为htmnl5并没有得到所有的浏览器的支持,所以如果你在不支持websocket的浏览器上,那么狠遗憾,就无法进行通信了【拒绝握手】。 接下来看下代码: 客户端 【client.html】 ``` <!DOCTYPE html> <html lang="en"> <head> <title>websocket+html5</title> <meta charset="utf-8"> </head> <script type="text/javascript"> //服务端地址 var server = 'ws://127.0.0.1:8888'; //握手 ws = new WebSocket(server); //握手成功 触发 ws.onopen = function(evt) { console.log(evt); alert('握手成功'); //ws.send("SENT"); }; //有消息来 触发 ws.onmessage = function (evt) { alert(1); console.log(evt.data); }; </script> <body> </body> </html> ``` 服务端【server.php】 ``` <?php //抑制超时 set_time_limit(0); //建立一个socket连接 $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); //阻塞模式 socket_set_block($sock) or die("socket_set_block() 失败的原因是:" . socket_strerror(socket_last_error()) . "/n"); //绑定一个通信地址以及端口 socket_bind($sock, '127.0.0.1', 8888); //监听该socket socket_listen($sock,3); $sockets = array('127.0.0.1' => $sock); //创建一个进程进行监听 while (true) { $sockets_res = array_values($sockets); $write = $except = NULL; $flag = socket_select($sockets_res, $write, $except, NULL); var_dump($flag); if (!$flag) { continue ; } //接收一个客户端连接 //客户端ip $ip = getHostByName(getHostName()); if (!isset($sockets[$ip])) { //该客户端还未连接,则进行握手操作 $any_sock = socket_accept($sock); $sockets[$ip] = $any_sock; upgrade($any_sock); } else { //握手成功,通信过程 //TODO } //关闭套接字资源 //socket_close($any_sock); } socket_close($sock); function upgrade($any_sock) { //服务端和客户端握手,握手方式看下方引用 $buffer = socket_read($any_sock, 2048); preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$buffer,$match); //握手 //GUID RFC4122 字符串 $guid_key = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; $key = base64_encode(sha1($match[1] . $guid_key, true)); $upgrade = "HTTP/1.1 101 Switching Protocol\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Accept: " . $key . "\r\n\r\n"; //必须以两个回车结尾 socket_write($any_sock, $upgrade, strlen($upgrade)); //socket_getpeername($socket, $ip, $port); $msg = [ 'type' => 'handshake', 'content' => 'done', ]; $msg = build(json_encode($msg)); socket_write($any_sock, $msg, strlen($msg)); } ?> ``` > 客户端握手请求中的 Sec-WebSocket-Key 头字段中的内容是采用的 base64 编码 RFC4648 的。服务端并不需要将这个值进行反编码,只需要将客户端传来的这个值首先去除首尾的空白,然后和一段固定的 GUID RFC4122 字符串进行连接,固定的 GUID 字符串为 258EAFA5-E914-47DA-95CA-C5AB0DC85B11。连接后的结果使用 SHA-1(160数位)FIPS.180-3 进行一个哈希操作,对哈希操作的结果,采用 base64 进行编码,然后作为服务端响应握手的一部分返回给浏览器。 WebSocket 协议: http://www.jianshu.com/p/867274a5e054 在cli模式下,执行 ``` php server.php ``` ,直接访问client.html,则会看到握手成功。 从以上代码可以看出,在客户端和服务端握手过程中主要还是通过http协议,那么握手成功后的通信过程就主要依靠websocket了。
NANGO
首 页
编程
聊天室
简介:
欢迎大家光临nango的博客,该博客由NoneCms搭建而成。
文章分类
PHP
js
centos
Python
MySQL
Laravel
最新文章
NoneCms 重大bug更新
docker compose编排的php开发环境
NoneCms 基于workerman的聊天室具体使用
centos7 + sendmail + php mail()函数实现邮件发送
文章归档
2018-12 (2)
2018-09 (1)
2018-01 (1)
2017-10 (1)
2017-07 (2)
2017-06 (2)
2017-03 (1)
2017-02 (2)
2017-01 (2)
2016-11 (4)
2016-10 (5)
2016-09 (3)
您的浏览器不支持 canvas.
© Nango
NANGO
文章分类