费话少说,用源代码说话

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>

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 } 测试  $ws = new WS("127.0.0.1",2000);

PHP 简单实现webSocket的更多相关文章

  1. 用 Go 编写一个简单的 WebSocket 推送服务

    用 Go 编写一个简单的 WebSocket 推送服务 本文中代码可以在 github.com/alfred-zhong/wserver 获取. 背景 最近拿到需求要在网页上展示报警信息.以往报警信息 ...

  2. 【node+小程序+web端】简单的websocket通讯

    [node+小程序+web端]简单的websocket通讯 websoket是用来做什么的? 聊天室 消息列表 拼多多 即时通讯,推送, 实时交互 websoket是什么 websocket是一个全新 ...

  3. springboot搭建一个简单的websocket的实时推送应用

    说一下实用springboot搭建一个简单的websocket 的实时推送应用 websocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 我们以前用的http协议只能单 ...

  4. python简单实现websocket

    协议选择的是新的Hybi-10,参考文章如下: http://www.cnblogs.com/zhuweisky/p/3930780.html http://blog.mycolorway.com/2 ...

  5. 实现一个简单的WebSocket聊天室

    WebSocket 简介 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主 ...

  6. 简单聊聊WebSocket

    一.概述 上一篇文章<浅析一次HTTP请求>我们分析了简单的一次 HTTP 请求具体是怎么样完成的,分析了 HTTP 协议的数据结构,如何连接,如何断开,又是如何多路复用的,那么今天我们来 ...

  7. 用Java构建一个简单的WebSocket聊天项目之新增HTTP接口调度

    采用框架 我们整个Demo基本不需要大家花费太多时间,就可以实现以下的功能. 用户token登录校验 自我聊天 点对点聊天 群聊 获取在线用户数与用户标签列表 发送系统通知 首先,我们需要介绍一下我们 ...

  8. WebSocket简单介绍(WebSocket 实战)(3)

    这一节里我们用一个案例来演示怎么使用 WebSocket 构建一个实时的 Web 应用.这是一个简单的实时多人聊天系统,包括客户端和服务端的实现.客户端通过浏览器向聊天服务器发起请求,服务器端解析客户 ...

  9. WebSocket简单介绍(WebSocket JavaScript 接口)(2)

    上一节介绍了 WebSocket 规范,其中主要介绍了 WebSocket 的握手协议.握手协议通常是我们在构建 WebSocket 服务器端的实现和提供浏览器的WebSocket 支持时需要考虑的问 ...

  10. 使用node+vue实现简单的WebSocket聊天功能

    最近学习了一下websocket的即时通信,感觉非常的强大,这里我用node启动了一个服务进行websocket链接,然后再vue的view里面进行了链接,进行通信,废话不多说,直接上代码吧, 首先, ...

随机推荐

  1. poj3468线段树标记永久化

    #include<map> #include<set> #include<list> #include<cmath> #include<queue ...

  2. Javascript鼠标和滚轮事件

    (转自:http://www.cnblogs.com/MrBackKom/archive/2012/06/25/2562920.html) a)鼠标事件 鼠标事件也许是web页面当中最常用到的事件,因 ...

  3. windows7自动登录后锁定 & 其他VBS

    首先设置自动登录(原已设置登录密码),在开始菜单搜索框输 入 “netplwiz” 按 回车,打开高级用户控制面板,然后取消对“要使用本机,用户需输入用户名和密码(E)”项的勾选,系统弹出窗口要求输入 ...

  4. Struts2 用过滤器代替了 servlet ,???? 且不需要tomcat就可以直接做功能测试

    Struts2  用过滤器代替了 servlet ,????  且不需要tomcat就可以直接做功能测试

  5. Flask--信号 blinker

    Flask--信号 blinker Flask框架中的信号基于blinker,可以让开发者在flask请求过程中 定制一些用户行为执行. 在请求前后,模板渲染前后,上下文前后,异常 的时候 安装: p ...

  6. H264提供了哪些帧内预测?

    H.264/AVC 提供了四种帧内预测方式:4x4 亮度块的帧内预测(Intra_4x4).16x16 亮度块的帧内预测(Intra_16x16).8x8 色度块的帧内预测(Intra_chroma) ...

  7. 提高看log效率的小工具

    文本型的log,比如Android的log,都是普通文本.在大家连续奋战的时候,难免看起来容易眼花. 这时候如何提高效率?我们给它搞个高亮好不好? 这就是我们要介绍的看log工具:TextAnalys ...

  8. beego数据输出

    beego数据输出   概览 直接输出字符串 模板数据输出 静态模板数据输出 动态模板数据输出 json格式数据输出 xml格式数据输出 jsonp调用 概览 直接输出字符串 通过beego.Cont ...

  9. (一)canvas简介

    <canvas>元素主要用来图形的绘制,通过脚本来完成(通常时js来实现): 可以利用其实现图表,游戏等项目的开发. getContext 获取画布的摸板是2d还是3d strokeRec ...

  10. 21天学通C++_Day3_Part1

    今天奔跑吧兄弟来杭电了,决定不去看,宅在科协继续啃(反正去了也看不到咯),继续继续,今天白天没课,希望可以更两个. 0.C风格字符串 在数组中间把某个字符替换成‘\0’并不会改变数组的长度,但是显示时 ...