您的位置:首页 > 编程语言 > PHP开发

php实现websocket实时消息推送

2017-10-25 14:05 681 查看
php实现websocket实时消息推送



SocketService.php

<?php
/**
* Created by xwx
* Date: 2017/10/18
* Time: 14:33
*/

class SocketService
{
private $address  = '0.0.0.0';
private $port = 8083;
private $_sockets;
public function __construct($address = '', $port='')
{
if(!empty($address)){
$this->address = $address;
}
if(!empty($port)) {
$this->port = $port;
}
}

public function service(){
//获取tcp协议号码。
$tcp = getprotobyname("tcp");
$sock = socket_create(AF_INET, SOCK_STREAM, $tcp);
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
if($sock < 0)
{
throw new Exception("failed to create socket: ".socket_strerror($sock)."\n");
}
socket_bind($sock, $this->address, $this->port);
socket_listen($sock, $this->port);
echo "listen on $this->address $this->port ... \n";
$this->_sockets = $sock;
}

public function run(){
$this->service();
$clients[] = $this->_sockets;
while (true){
$changes = $clients;
$write = NULL;
$except = NULL;
socket_select($changes,  $write,  $except, NULL);
foreach ($changes as $key => $_sock){
if($this->_sockets == $_sock){ //判断是不是新接入的socket
if(($newClient = socket_accept($_sock))  === false){
die('failed to accept socket: '.socket_strerror($_sock)."\n");
}
$line = trim(socket_read($newClient, 1024));
$this->handshaking($newClient, $line);
//获取client ip
socket_getpeername ($newClient, $ip);
$clients[$ip] = $newClient;
echo  "Client ip:{$ip}   \n";
echo "Client msg:{$line} \n";
} else {
socket_recv($_sock, $buffer,  2048, 0);
$msg = $this->message($buffer);
//在这里业务代码
echo "{$key} clinet msg:",$msg,"\n";
fwrite(STDOUT, 'Please input a argument:');
$response = trim(fgets(STDIN));
$this->send($_sock, $response);
echo "{$key} response to Client:".$response,"\n";
}
}
}
}

/**
* 握手处理
* @param $newClient socket
* @return int  接收到的信息
*/
public function handshaking($newClient, $line){

$headers = array();
$lines = preg_split("/\r\n/", $line);
foreach($lines as $line)
{
$line = chop($line);
if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
{
$headers[$matches[1]] = $matches[2];
}
}
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $this->address\r\n" .
"WebSocket-Location: ws://$this->address:$this->port/websocket/websocket\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
return socket_write($newClient, $upgrade, strlen($upgrade));
}

/**
* 解析接收数据
* @param $buffer
* @return null|string
*/
public function message($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;
}

/**
* 发送数据
* @param $newClinet 新接入的socket
* @param $msg   要发送的数据
* @return int|string
*/
public function send($newClinet, $msg){
$msg = $this->frame($msg);
socket_write($newClinet, $msg, strlen($msg));
}

public 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;
}

/**
* 关闭socket
*/
public function close(){
return socket_close($this->_sockets);
}
}

$sock = new SocketService();
$sock->run();
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
147
148
149
150
151
152
153
154
155
156
web.html

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
<title>websocket</title>
</head>
<body>
<input id="text" value="">
<input type="submit" value="send" onclick="start()">
<input type="submit" value="close" onclick="close()">
<div id="msg"></div>
<script>
/**
0:未连接

1:连接成功,可通讯

2:正在关闭

3:连接已关闭或无法打开
*/

//创建一个webSocket 实例
var webSocket  = new  WebSocket("ws://192.168.31.152:8083");

webSocket.onerror = function (event){
onError(event);
};

// 打开websocket
webSocket.onopen = function (event){
onOpen(event);
};

//监听消息
webSocket.onmessage = function (event){
onMessage(event);
};

webSocket.onclose = function (event){
onClose(event);
}

//关闭监听websocket
function onError(event){
document.getElementById("msg").innerHTML = "<p>close</p>";
console.log("error"+event.data);
};

function onOpen(event){
console.log("open:"+sockState());
document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";
};
function onMessage(event){
console.log("onMessage");
document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"
};

function onClose(event){
document.getElementById("msg").innerHTML = "<p>close</p>";
console.log("close:"+sockState());
webSocket.close();
}

function sockState(){
var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
return status[webSocket.readyState];
}

function start(event){
console.log(webSocket);
var msg = document.getElementById('text').value;
document.getElementById('text').value = '';
console.log("send:"+sockState());
console.log("msg="+msg);
webSocket.send("msg="+msg);
document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"
};

function close(event){
webSocket.close();
}
</script>
</body>
</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: