我做的一个websocket的demo(php server)

复制代码

notice:

通过命令行执行php文件  如 php -q c:\path\server.php 

通过本地web服务器访问 http://127.0.0.1/websocket/index.php即可

notice: 
需要php5.3或以上的执行环境,和一个web服务器如apache
浏览器需支持html5 web socket
这里监听 socket端口 9505,如遇到端口被占用可能需要在这两个文件内修改端口或者杀死相应端口进程

页面手机上看起来比pc上好看!

1.客户端代码 html文件

2.socket服务器端代码 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
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
2.php code:
<?php
$host = '127.0.0.1';
$port = '9505';
$null = NULL;
 
//创建tcp socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
 
//监听端口
socket_listen($socket);
 
//连接的client socket 列表
$clients = array($socket);
 
//设置一个死循环,用来监听连接 ,状态
while (true) {
     
    $changed = $clients;
    socket_select($changed, $null, $null, 0, 10);
     
    //如果有新的连接
    if (in_array($socket, $changed)) {
        //接受并加入新的socket连接
        $socket_new = socket_accept($socket);
        $clients[] = $socket_new;
         
        //通过socket获取数据执行handshake
        $header = socket_read($socket_new, 1024);
        perform_handshaking($header, $socket_new, $host, $port);
         
        //获取client ip 编码json数据,并发送通知
        socket_getpeername($socket_new, $ip);
        $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));
        send_message($response);
        $found_socket = array_search($socket, $changed);
        unset($changed[$found_socket]);
    }
     
    //轮询 每个client socket 连接
    foreach ($changed as $changed_socket) {   
         
        //如果有client数据发送过来
        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
        {
            //解码发送过来的数据
            $received_text = unmask($buf);
            $tst_msg = json_decode($received_text); 
            $user_name = $tst_msg->name;
            $user_message = $tst_msg->message;
             
            //把消息发送回所有连接的 client 上去
            $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message)));
            send_message($response_text);
            break 2;
        }
         
        //检查offline的client
        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) {
            $found_socket = array_search($changed_socket, $clients);
            socket_getpeername($changed_socket, $ip);
            unset($clients[$found_socket]);
            $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
            send_message($response);
        }
    }
}
// 关闭监听的socket
socket_close($sock);
 
//发送消息的方法
function send_message($msg)
{
    global $clients;
    foreach($clients as $changed_socket)
    {
        @socket_write($changed_socket,$msg,strlen($msg));
    }
    return true;
}
 
 
//解码数据
function unmask($text) {
    $length = ord($text[1]) & 127;
    if($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    }
    elseif($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    }
    else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}
 
//编码数据
function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);
     
    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$text;
}
 
//握手的逻辑
function perform_handshaking($receved_header,$client_conn, $host, $port)
{
    $headers = array();
    $lines = preg_split("/\r\n/", $receved_header);
    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: $host\r\n" .
    "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn,$upgrade,strlen($upgrade));
}

  

复制代码
2.php code:
<?php
$host = '127.0.0.1'; 
$port = '9505'; 
$null = NULL; 

//创建tcp socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);

//监听端口
socket_listen($socket);

//连接的client socket 列表
$clients = array($socket);

//设置一个死循环,用来监听连接 ,状态
while (true) {
    
    $changed = $clients;
    socket_select($changed, $null, $null, 0, 10);
    
    //如果有新的连接
    if (in_array($socket, $changed)) {
        //接受并加入新的socket连接
        $socket_new = socket_accept($socket); 
        $clients[] = $socket_new;
        
        //通过socket获取数据执行handshake
        $header = socket_read($socket_new, 1024); 
        perform_handshaking($header, $socket_new, $host, $port);
        
        //获取client ip 编码json数据,并发送通知
        socket_getpeername($socket_new, $ip);
        $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));
        send_message($response);
        $found_socket = array_search($socket, $changed);
        unset($changed[$found_socket]);
    }
    
    //轮询 每个client socket 连接
    foreach ($changed as $changed_socket) {    
        
        //如果有client数据发送过来
        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
        {
            //解码发送过来的数据
            $received_text = unmask($buf); 
            $tst_msg = json_decode($received_text);  
            $user_name = $tst_msg->name; 
            $user_message = $tst_msg->message; 
            
            //把消息发送回所有连接的 client 上去
            $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message)));
            send_message($response_text);
            break 2; 
        }
        
        //检查offline的client
        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) { 
            $found_socket = array_search($changed_socket, $clients);
            socket_getpeername($changed_socket, $ip);
            unset($clients[$found_socket]);
            $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
            send_message($response);
        }
    }
}
// 关闭监听的socket
socket_close($sock);

//发送消息的方法
function send_message($msg)
{
    global $clients;
    foreach($clients as $changed_socket)
    {
        @socket_write($changed_socket,$msg,strlen($msg));
    }
    return true;
}


//解码数据
function unmask($text) {
    $length = ord($text[1]) & 127;
    if($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    }
    elseif($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    }
    else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}

//编码数据
function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);
    
    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$text;
}

//握手的逻辑
function perform_handshaking($receved_header,$client_conn, $host, $port)
{
    $headers = array();
    $lines = preg_split("/\r\n/", $receved_header);
    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: $host\r\n" .
    "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn,$upgrade,strlen($upgrade));
}
复制代码
复制代码

posted on   一坪海岸线y  阅读(362)  评论(0编辑  收藏  举报

编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· DeepSeek+PageAssist实现本地大模型联网
· 手把手教你更优雅的享受 DeepSeek
· 腾讯元宝接入 DeepSeek R1 模型,支持深度思考 + 联网搜索,好用不卡机!
· 从 14 秒到 1 秒:MySQL DDL 性能优化实战
· AI工具推荐:领先的开源 AI 代码助手——Continue
历史上的今天:
2016-08-21 PHP中“==”运算符的安全问题
2016-08-21 一些需要禁用的PHP危险函数
2016-08-21 使用PHP QR Code生成二维码

导航

< 2025年2月 >
26 27 28 29 30 31 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 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示