在socket出现之前已经有ajax定时请求、长轮询等方案,但都不能满足需求,socket就应用而生了。
socket基本函数socket
总结下常用的socket函数
服务端: socket_create 创建socket设置基本参数
socket_bind 绑定ip和端口号
socket_listen 监听
socket_accept 客户端的连接
socket_read 读取客户端的数据
socket_write 给单独客户端发送数据
socket_close 关闭连接
客户端:socket_create 创建socket设置基本参数
socket_connect 连接socket
socket_write 给服务端发送数据
socket_read 读取服务端数据
socket_close 关闭连接
H5websocket不多说了,上链接
OK,开始贴代码~
----------------------------------------------------------分割线
服务端代码:
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
<? php
class WS {
var $master;
var $ sockets = array ();
var $ debug = false ;//true为调试模式,输出log日志
var $ handshake = array ();
function __construct($address, $port){
$this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($this->master, $address, $port) or die("socket_bind() failed");
socket_listen($this->master,20) or die("socket_listen() failed");
$this->sockets[] = $this->master;
$this->say("Server Started : ".date('Y-m-d H:i:s'));
$this->say("Listening on : ".$address." port ".$port);
$this->say("Master socket : ".$this->master."\n");
while(true){
$socketArr = $this->sockets;
$write = NULL;
$except = NULL;
socket_select($socketArr, $write, $except, NULL); //自动选择来消息的socket 如果是握手 自动选择主机
foreach ($socketArr as $socket){
if ($socket == $this->master){ //主机
$client = socket_accept($this->master);
if ($client < 0 ){
$this->log("socket_accept() failed");
continue;
} else{
$this->connect($client);
}
} else {
$bytes = @socket_recv($socket,$buffer,2048,0);
if ($bytes == 0){
$this->disConnect($socket);
}
else{
$key = array_search($socket, $this->sockets);
if (empty($this->handshake) || !isset($this->handshake[$key]) || !$this->handshake[$key]){
$this->doHandShake($socket, $buffer, $key);
}
else{
$buffer = $this->decode($buffer);
echo $buffer.PHP_EOL;
$key = array_search($socket, $this->sockets);
$arr = $this->sockets;
array_shift($arr);
foreach ($arr as $s){
$this->send($s, $buffer);
}
}
}
}
}
}
}
function send($client, $msg){
$msg = $this->frame($msg);
socket_write($client, $msg, strlen($msg));
}
function connect($socket){
array_push($this->sockets, $socket);
$this->say("\n" . $socket . " CONNECTED!");
$this->say(date("Y-n-d H:i:s"));
}
function disConnect($socket){
$index = array_search($socket, $this->sockets);
socket_close($socket);
$this->say($socket . " DISCONNECTED!");
if ($index >= 0){
echo 'unset index is:'.PHP_EOL;
unset($this->sockets[$index]);
}
}
function doHandShake($socket, $buffer, $handKey){
$this->log("\nRequesting handshake...");
$this->log($buffer);
list($resource, $host, $origin, $key) = $this->getHeaders($buffer);
$this->log("Handshaking...");
$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾
$this->log($upgrade);
$sent = socket_write($socket, $upgrade, strlen($upgrade));
$this->handshake[$handKey]=true;
$this->log("Done handshaking...");
return true;
}
function getHeaders($req){
$r = $h = $o = $key = null;
if (preg_match("/GET (.*) HTTP/" ,$req,$match)) { $r = $match[1]; }
if (preg_match("/Host: (.*)\r\n/" ,$req,$match)) { $h = $match[1]; }
if (preg_match("/Origin: (.*)\r\n/" ,$req,$match)) { $o = $match[1]; }
if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)) { $key = $match[1]; }
return array($r, $h, $o, $key);
}
function calcKey($key){
//基于websocket version 13
$accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
return $accept;
}
function decode($buffer) {
$len = $masks = $data = $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 frame($s){
$ a = str_split ($s, 125);
if (count($a) == 1){
return "\x81" . chr(strlen($a[0])) . $a[0];
}
$ ns = "" ;
foreach ($a as $o){
$ns . = "\x81" . chr(strlen($o)) . $o;
}
return $ns;
}
function say($ msg = "" ){
echo $msg . "\n";
}
function log($ msg = "" ){
if ($this->debug){
echo $msg . "\n";
}
}
}
new WS('localhost', 4000);
|
客户端代码(H5):
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
|
< html >
< head >
< title >demo</ title >
< script src = "https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js" ></ script >
</ head >
< body >
< input type = "text" id = "content" >
< input type = "button" value = "send" id = "send" >
< script type = "text/javascript" >
var ws = new WebSocket("ws://localhost:4000");
ws.onopen = function(){
console.log("握手成功");
}
ws.onmessage = function(e){
console.log("message:" + e.data);
}
ws.onerror = function(){
console.log("error");
}
$("#send").click(function(){
content = $("#content").val();
console.log(content);
ws.send(content);
})
</ script >
</ body >
</ html >
|
然后执行php demo.php 开启socket(从运维那偷学一招,linux下执行nohup php demo.php &可以在后台执行),浏览器打开多个index.html,就能建立通讯了。
代码解析:
1.属性$sockets数组保存每个accept连接(不知道这么描述对不对);
2.属性$handshake数组保存连接是否在连接状态;
以上这篇php实现socket推送技术的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/kkform/archive/2017/12/20/8072836.html