对我来说最快的学习途径是实践,所以找两个东西来练手。一个是websocket一个是webwoker,今天先说第一个。

要理解socket就要先理解http和tcp的区别,简单说就是一个是短链,一个是长链,一个是去服务器拉数据,一个是服务器可以主动推数据。

而socket就是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。-来自网络。

那么如何用php+js做到服务器推呢?

客户端

客户端非常简单,利用现代浏览器的WebSocket API,这里介绍的很详细:http://msdn.microsoft.com/zh-cn/library/ie/hh673567

核心代码:

JAVASCRIPT

1
2
3
4
5
var wsServer = 'ws://127.0.0.1:8080';
var ws = new WebSocket(wsServer);
ws.onmessage = function (evt) {
do sth
};

前两行会向指定服务器发送一个握手请求,如果服务器返回合法的http头,则握手成功,之后可通过监听onmessage事件来处理服务器发来的消息。还有很多其他事件可监听,见前面的url。

服务器

思路

难点是服务器,没有了apache和nginx这些http服务器在前面顶着,只用php该怎么写?

这里有个教程讲的很深入 http://blog.csdn.net/shagoo/article/details/6396089

写之前捋一捋思路:

1 监听:首先要挂起一个进程来监听来自客户端的请求 
2 握手:对于第一次合法的请求,发送合法的header回去 
3 保持连接:有新消息到了就广播出去。直到客户端断开 
4 接受另一个请求,重复2和3

代码如下:

PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public function start_server() {
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//允许使用本地地址
socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, TRUE);
socket_bind($this->socket, $this->host, $this->port);
//最多10个人连接,超过的客户端连接会返回WSAECONNREFUSED错误
socket_listen($this->socket, $this->maxuser);
while(TRUE) {
$this->cycle = $this->accept;
$this->cycle[] = $this->socket;
//阻塞用,有新连接时才会结束
socket_select($this->cycle, $write, $except, null);
foreach ($this->cycle as $k => $v) {
if($v === $this->socket) {
if (($accept = socket_accept($v)) < 0) {
continue;
}
//如果请求来自监听端口那个套接字,则创建一个新的套接字用于通信
$this->add_accept($accept);
continue;
}
$index = array_search($v, $this->accept);
if ($index === NULL) {
continue;
}
if (!@socket_recv($v, $data, 1024, 0) || !$data) {//没消息的socket就跳过
$this->close($v);
continue;
}
if (!$this->isHand[$index]) {
$this->upgrade($v, $data, $index);
if(!empty($this->function['add'])) {
call_user_func_array($this->function['add'], array($this));
}
continue;
}
$data = $this->decode($data);
if(!empty($this->function['send'])) {
call_user_func_array($this->function['send'], array($data, $index, $this));
}
}
sleep(1);
}
}
//增加一个初次连接的用户
private function add_accept($accept) {
$this->accept[] = $accept;
$index = array_keys($this->accept);
$index = end($index);
$this->isHand[$index] = FALSE;
}
//关闭一个连接
private function close($accept) {
$index = array_search($accept, $this->accept);
socket_close($accept);
unset($this->accept[$index]);
unset($this->isHand[$index]);
if(!empty($this->function['close'])) {
call_user_func_array($this->function['close'], array($this));
}
}
//响应升级协议
private function upgrade($accept, $data, $index) {
if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$data,$match)) {
$key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 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($accept, $upgrade, strlen($upgrade));
$this->isHand[$index] = TRUE;
}
}

关键地方有那么几个,一是while(true)挂起进程,不然执行一次后进程就退出了。二是socket_select和socket_accept函数的使用。三是客户端第一次请求时握手。

socket_select

这个函数是同时接受多个连接的关键,我的理解它是为了阻塞程序继续往下执行。

socket_select ($sockets, $write = NULL, $except = NULL, NULL);

$sockets可以理解为一个数组,这个数组中存放的是文件描述符。当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。 
$write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。 
$except是$sockets里面要被排除的元素,传入NULL是”监听”全部。 
最后一个参数是超时时间 
如果为0:则立即结束 
如果为n>1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回 
如果为null:如遇某一个连接有新动态,则返回

socket_accept

此函数接受唯一参数,即前面socket_create创建的socket文件(句柄)。返回一个新的资源,或者FALSE。本函数将会通知socket_listen(),将会传入一个连接的socket资源。一旦成功建立socket连接,将会返回一个新的socket资源,用于通信。如果有多个socket在队列中,那么将会先处理第一个。关键就是这里:如果没有socket连接,那么本函数将会等待,直到有新socket进来。

如果前面不用socket_select在没有socket的时候阻塞住程序,那么就卡在这里永远无法结束了。

后面的流程就很清晰了,当有一个新的客户端请求到达,用socket_accept创建一个资源,并加入到$this->accept连接池里面。并将它的标示isHand设为false,那么下次循环(因为$this->cycle[] = $this->socket;$this->cycle有变化,所以socket_select会返回)的时候就会执行upgrade握手。然后等待它的新消息即可。

程序经调试可以成功运行,php5.3+websocket13。有兴趣的同学可以下载:文件地址

websocket webworker的更多相关文章

  1. WebWorker与WebSocket实现前端消息总线

    Web Worker让JS有了多线程的能力,可以将复杂耗时的操作都交付给Worker线程处理.WebSocket让web端与服务端维持一个有效的长连接,实现服务端主动推送数据.将二者一结合,业务系统信 ...

  2. 结合WebSocket编写WebGL综合场景示例

    在WebGL场景中导入多个Babylon骨骼模型,在局域网用WebSocket实现多用户交互控制. 首先是场景截图: 上图在场景中导入一个Babylon骨骼模型,使用asdw.空格.鼠标控制加速度移动 ...

  3. WebWorker 简单使用方式

    WebWorker 一定程度上可以算得上是浏览器中的多线程技术了,在项目中适当使用 Worker 来做一些耗时的操作能大大提高页面整体流畅度. Worker的使用也是非常简单的,通过向 Worker ...

  4. JS多线程WebWorker

    JS多线程WebWorker 一,介绍与需求 1.1,介绍 Web Worker可以为JavaScript创建多线程,且Web Worker 是运行在后台的 JavaScript,独立于其他脚本,不会 ...

  5. 漫扯:从polling到Websocket

    Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...

  6. 细说WebSocket - Node篇

    在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. WebSocket - ( 一.概述 )

    说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...

  9. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

随机推荐

  1. c++ std::string 用法

    std::string用法总结 在平常工作中经常用到了string类,本人记忆了不好用到了的时候经常要去查询.在网上摘抄一下总结一下,为以后的查询方便: string类的构造函数: string(co ...

  2. bzoj 4010: [HNOI2015]菜肴制作 拓扑排序

    题目链接: 题目 4010: [HNOI2015]菜肴制作 Time Limit: 5 Sec Memory Limit: 512 MB 问题描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴 ...

  3. 【POJ】【3537】Crosses and Crosses

    博弈论 相当于放了x的位置,左右4格都不能再放x了,谁无处可放就输. n<=2000 直接枚举后继状态,暴力求SG函数即可. 例: 0000000->x..0000 / .x..000 / ...

  4. hlsl 和cg 涉及 mul 左乘 右乘

    error: 1. mul' implicit truncation of vector type 2. matrixXXX: array dimensions of(unknown scope en ...

  5. KASS分布式文件系统(Kass File System)

    KASS分布式文件系统(Kass File System),简称KFS,是开始公司自主研发的分布式文件存储服务平台.KFS系统架构及功能服务类似Hadoop/GFS/DFS,它通过HTTP-WEB为上 ...

  6. 【WCF--初入江湖】目录

    [WCF--初入江湖]目录 [WCF--初入江湖]01 WCF编程概述 [WCF--初入江湖]02 WCF契约 [WCF--初入江湖]03 配置服务 [WCF--初入江湖]04 WCF通信模式 [WC ...

  7. UVA 11174 Stand in a Line (组合+除法的求模)

    题意:村子里有n个人,给出父亲和儿子的关系,有多少种方式可以把他们排成一列,使得没人会排在他父亲的前面 思路:设f[i]表示以i为根的子树有f[i]种排法,节点i的各个子树的根节点,即它的儿子为c1, ...

  8. **bootstrap常见常用样式总结

    1.水平居中 用 .text-center 类

  9. hdu 2486/2580 / poj 3922 A simple stone game 博弈论

    思路: 这就是K倍动态减法游戏,可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文. 首先k=1的时候,必败态是2^i,因为我们把数二进制分解后,拿掉最后一个1,那么会导致对方永远也取 ...

  10. [转] 软件定义网络(SDN) 的应运而生

    原文见51CTO:http://network.51cto.com/art/201103/251425.htm 2012的故事 2012年的某天,你跟往常一样起床,打开电脑,却发现无法登录到邮箱.无法 ...