热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHPSocket编程基础入门——实例WebSocket通信演示

目前的代码只适合一个人用,逻辑中排斥多用户1、服务端




目前的代码只适合一个人用,逻辑中排斥多用户
1、服务端


/**
* php /data/www/g-mall/test.gsj.com/websocket/socket_server.php
* 浏览器打开 http://test.gsj.com/websocket/socket_client.html
* Class SocketService
*/

class SocketService
{
private $address;//ip地址
private $port;//端口
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 ( resource $socket , int $level , int $optname , mixed $optval )用法说明:
//函数将 optname 参数在指定的 protocollevel 上指定的选项设置为该套接字的 optval 参数所指向的值
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
if ($sock < 0) {
throw new Exception("failed to create socket: " . socket_strerror($sock) . "\n");
}
//绑定端口和ip
socket_bind($sock, $this->address, $this->port);
//在具体的地址下监听 socket 资源的收发操作
socket_listen($sock, $this->port);

// echo "listen on $this->address $this->port ... \n";
$this->_sockets &#61; $sock;
}
//运行
public function run()
{
//创建
$this->service();
//获取客户端
$clients[] &#61; $this->_sockets;

while (true) {
$changes &#61; $clients;
$write &#61; NULL;
$except &#61; NULL;

//在指定的超时时间内对给定的套接字数组运行select&#xff08;&#xff09;系统调用
socket_select($changes, $write, $except, NULL);
//
foreach ($changes as $key &#61;> $_sock) {
echo $_sock;
if ($this->_sockets &#61;&#61; $_sock) { //判断是不是新接入的socket
//socket_accept 接收一个新的 socket 资源 函数原型
if (($newClient &#61; socket_accept($_sock)) &#61;&#61;&#61; false) {
die(&#39;failed to accept socket: &#39; . socket_strerror($_sock) . "\n");
}
//socket_read 获取传送的数据 函数原型$newClient 1024长度
$line &#61; trim(socket_read($newClient, 1024));
//握手处理
$this->handshaking($newClient, $line);
//获取client ip 查询给定套接字的远程端&#xff0c;可能返回主机端口或者Unix文件系统路径&#xff08;取决于socket_create设置的类型&#xff09;
socket_getpeername($newClient, $ip);
$clients[$ip] &#61; $newClient;

} else {
//函数 socket_recv() 从 socket 中接收长度为 length 字节的数据&#xff0c;并保存在 data 中
socket_recv($_sock, $buffer, 2048, 0);
//解析接收数据
$msg &#61; $this->message($buffer);
//在这里业务代码
echo "{$key} clinet msg:", $msg, "\n";
// fwrite(STDOUT, &#39;Please input a argument:&#39;);
// $response &#61; trim(fgets(STDIN));
$response&#61;"接受了";
//发送
$this->send($_sock, $response);
echo "{$key} response to Client:" . $response, "\n";
}
}
}
}
/**
* 握手处理
* &#64;param $newClient socket
* &#64;return int 接收到的信息
*/

public function handshaking($newClient, $line)
{
$headers &#61; array();
//$line消息
$lines &#61; preg_split("/\r\n/", $line);
foreach ($lines as $line) {
$line &#61; chop($line);

if (preg_match(&#39;/\A(\S&#43;): (.*)\z/&#39;, $line, $matches)) {
$headers[$matches[1]] &#61; $matches[2];
}
}
//首先&#xff0c; Sec-WebSocket-Key
//是一个 Base64 的值&#xff0c;这个是浏览器随机生成的&#xff0c;告诉服务器&#xff1a; &#xff0c;我要验证尼是不是真的是Websocket助理
$secKey &#61; $headers[&#39;Sec-WebSocket-Key&#39;];
$secAccept &#61; base64_encode(pack(&#39;H*&#39;, sha1($secKey . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;)));
$upgrade &#61; "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));
}
/**
* 解析接收数据
* &#64;param $buffer
* &#64;return null|string
*/

public function message($buffer)
{
$len &#61; $masks &#61; $data &#61; $decoded &#61; null;
$len &#61; ord($buffer[1]) & 127;
if ($len &#61;&#61;&#61; 126) {
$masks &#61; substr($buffer, 4, 4);
$data &#61; substr($buffer, 8);
} else if ($len &#61;&#61;&#61; 127) {
$masks &#61; substr($buffer, 10, 4);
$data &#61; substr($buffer, 14);
} else {
$masks &#61; substr($buffer, 2, 4);
$data &#61; substr($buffer, 6);
}
for ($index &#61; 0; $index < strlen($data); $index&#43;&#43;) {
$decoded .&#61; $data[$index] ^ $masks[$index % 4];
}
return $decoded;
}
/**
* 发送数据
* &#64;param $newClinet 新接入的socket
* &#64;param $msg 要发送的数据
* &#64;return int|string
*/

public function send($newClinet, $msg)
{
$msg &#61; $this->frame($msg);
socket_write($newClinet, $msg, strlen($msg));
}
//转义处理
public function frame($s)
{
$a &#61; str_split($s, 125);
if (count($a) &#61;&#61; 1) {
return "\x81" . chr(strlen($a[0])) . $a[0];
}
$ns &#61; "";
foreach ($a as $o) {
$ns .&#61; "\x81" . chr(strlen($o)) . $o;
}
return $ns;
}
/**
* 关闭socket
*/

public function close()
{
return socket_close($this->_sockets);
}
}
$sock &#61; new SocketService(&#39;192.168.31.20&#39;, &#39;9000&#39;);
$sock->run();

命令行运行服务端&#xff1b;
2、客户端

doctype html>
<html lang&#61;"en">
<head>
<meta charset&#61;"UTF-8">
<meta name&#61;"viewport" content&#61;"width&#61;device-width,initial-scale&#61;1, maximum-scale&#61;1, user-scalable&#61;no">
<title>websockettitle>
head>
<body>
<input id&#61;"text" value&#61;"">
<input type&#61;"submit" value&#61;"send" onclick&#61;"start()">
<input type&#61;"submit" value&#61;"close" onclick&#61;"close()">
<div id&#61;"msg">div>
<script>
/**
*0&#xff1a;未连接
*1&#xff1a;连接成功&#xff0c;可通讯
*2&#xff1a;正在关闭
*3&#xff1a;连接已关闭或无法打开
*/

//创建一个webSocket 实例
var webSocket &#61; new WebSocket("ws://192.168.31.20:9000");
webSocket.onerror &#61; function (event) {
onError(event);
};
// 打开websocket
webSocket.onopen &#61; function (event) {
onOpen(event);
};
//监听消息
webSocket.onmessage &#61; function (event) {
onMessage(event);
};
webSocket.onclose &#61; function (event) {
onClose(event);
}
//关闭监听websocket
function onError(event) {
document.getElementById("msg").innerHTML &#61; "

close

";
console.log("error" &#43; event.data);
};
function onOpen(event) {
console.log("open:" &#43; sockState());
document.getElementById("msg").innerHTML &#61; "

Connect to Service

"
;
};
function onMessage(event) {
console.log("onMessage");
document.getElementById("msg").innerHTML &#43;&#61; "

response:" &#43; event.data &#43; "

"

};
function onClose(event) {
document.getElementById("msg").innerHTML &#61; "

close

"
;
console.log("close:" &#43; sockState());
webSocket.close();
}
function sockState() {
var status &#61; [&#39;未连接&#39;, &#39;连接成功&#xff0c;可通讯&#39;, &#39;正在关闭&#39;, &#39;连接已关闭或无法打开&#39;];
return status[webSocket.readyState];
}
function start(event) {
console.log(webSocket);
var msg &#61; document.getElementById(&#39;text&#39;).value;
document.getElementById(&#39;text&#39;).value &#61; &#39;&#39;;
console.log("send:" &#43; sockState());
console.log("msg&#61;" &#43; msg);
webSocket.send("msg&#61;" &#43; msg);
document.getElementById("msg").innerHTML &#43;&#61; "

request" &#43; msg &#43; "

"

};
function close(event) {
webSocket.close();
}
script>
body>
html>






推荐阅读
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 如何在PHP中准确获取服务器IP地址?
    如何在PHP中准确获取服务器IP地址? ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 本文探讨了利用Java实现WebSocket实时消息推送技术的方法。与传统的轮询、长连接或短连接等方案相比,WebSocket提供了一种更为高效和低延迟的双向通信机制。通过建立持久连接,服务器能够主动向客户端推送数据,从而实现真正的实时消息传递。此外,本文还介绍了WebSocket在实际应用中的优势和应用场景,并提供了详细的实现步骤和技术细节。 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 在PHP中如何正确调用JavaScript变量及定义PHP变量的方法详解 ... [详细]
  • SecureCRT是一款功能强大的终端仿真软件,支持SSH1和SSH2协议,适用于在Windows环境下高效连接和管理Linux服务器。该工具不仅提供了稳定的连接性能,还具备丰富的配置选项,能够满足不同用户的需求。通过SecureCRT,用户可以轻松实现对远程Linux系统的安全访问和操作。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 本指南详细介绍了在Linux环境中高效连接MySQL数据库的方法。用户可以通过安装并使用`mysql`客户端工具来实现本地连接,具体命令为:`mysql -u 用户名 -p 密码 -h 主机`。例如,使用管理员账户连接本地MySQL服务器的命令为:`mysql -u root -p pass`。此外,还提供了多种配置优化建议,以确保连接过程更加稳定和高效。 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • 在CentOS 7上部署WebRTC网关Janus
    在CentOS 7上部署WebRTC网关Janus ... [详细]
author-avatar
殇猿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有