websocket php教程

2023-09-21 17:47:46

WebSocket 是 HTML5 提供的一种网络通讯协议,用于服务端与客户端实时数据传输。广泛用于浏览器与服务器的实时通讯,APP与服务器的实时通讯等场景。

相比传统HTTP协议请求响应式通讯,WebSocket协议可以做到实时的双向通讯,服务端可以在任何时候向客户端推送数据(HTTP协议需要客户端发起请求后才能推送)。

PHP作为世界上最好的语言,自然支持WebSocket协议。以下是PHP使用WebSocket协议教程。

教程里使用workerman作为应用容器,workerman具备非常高的性能,它不仅支持WebSocket协议,也支持HTTP协议、Text协议、Frame协议以及其它自定义协议等。

年会PHP WebSocket实时大屏

想象一下我们年会上需要一个大屏,显示每一个公司成员对公司的祝福语。接下来我们就用workerman+WebSocket来实现它。

WebSocket数据流转图

首先我们需要整理下它的数据流转图。

员工(手机浏览器) <-------websocket------>[服务器]<------websocket------>大屏(电脑浏览器投屏)

原理比较简单,手机浏览器和电脑浏览器分别与服务器建立一个WebSocket连接。手机浏览器通过websocket发送文字祝福给服务器,服务器将文字祝福通过websocket推送给电脑浏览器并显示。

新建目录

新建目录 php-websocket,然后进入到 php-websocket 目录中

安装workerman

composer require workerman/workerman

新建一个start.php 文件

<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Connection\TcpConnection;

// 使用websocket协议监听6161端口
$worker = new Worker('websocket://0.0.0.0:6161');

//  当浏览器(包括用户手机浏览器和电脑浏览器)发来消息时的处理逻辑
$worker->onMessage = function(TcpConnection $connection, $data) {
    // 这个静态变量用来存储电脑浏览器的websocket连接,方便推送使用
    static $daping_connection = null;
    switch ($data) {
        // 发送 daping 字符串的是电脑浏览器,将其连接保存到静态变量中
        case 'daping':
            $daping_connection = $connection;
            break;
        // ping 是心跳数据,用来维持连接,只返回 pong 字符串,无需做其它处理
        case 'ping':
            $connection->send('pong');
            break;
        // 用户手机浏览器发来的祝福语
        default:
            // 直接使用电脑浏览器的连接将祝福语推送给电脑
            if ($daping_connection) {
                $daping_connection->send($data);
            }
    }
};
Worker::runAll();

我们看到服务端代码很简洁,电脑浏览器发起websocket连接后会发送一个字符串daping,告诉服务端我是电脑浏览器,服务端将这个连接保存到静态变量,方便给它推送数据。手机浏览器发送的数据会直接用静态变量保存的电脑浏览器连接推送过去。

我们注意到有一个心跳数据ping pong的交互,这是由于外网环境很复杂,连接如果长时间不通讯(超过1分钟)连接就会被路由节点、防火墙等断开,所以客户端与服务端需要在1分钟内至少通讯一次,避免连接断开,这个就是心跳的作用。

服务端开发完毕,接下来是客户端。

电脑浏览器大屏

新建 daping.html

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <script src="jquery.min.js"></script>
    <title>WebSocket大屏</title>
</head>
<body>
    <ul id="content">

    </ul>
</body>
<script>
    function connect() {
        // 与服务端建立WebSocket连接
        //(为了方便测试这里ip使用的是127.0.0.1,正式环境请使用外网ip)
        ws = new WebSocket('ws://127.0.0.1:6161');
        // 连接建立后发送daping,表明自己是电脑浏览器
        ws.onopen = function() {
            ws.send('daping');
        };
        //  收到服务端推送的数据后,将数据显示在浏览器里(心跳数据pong除外)
        ws.onmessage = function (e) {
            if (e.data !== 'pong') {
                $($('#content')).append('<li>'+e.data+'</li>');
            }
        };
        // 没隔50秒发送一个心跳数据 ping 给服务器,保持连接
        ws.timer = setInterval(function () {
            ws.send('ping');
        }, 50000);
        //  当连接关闭时清除定时器,并设置1秒后重连
        ws.onclose = function () {
            clearTimeout(ws.timer);
            setTimeout(connect, 1000);
        };
    }
    // 执行连接
    connect();
</script>
</html>

虽然我们做了心跳保持连接,但是仍然无法保证连接不被断开,比如用户将浏览器切到后台、网络信号差、服务端重启等。所以断线重连是长连接应用必备的功能。所以我们需要在客户端监听连接断开事件 ws.onclose,在这里执行一个定时器执行重连。

用户手机浏览器端

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>WebSocket大屏</title>
    <script src="jquery.min.js"></script>
</head>
<body>

<input type="text" id="content">
<input type="button" value="发送" onclick="send()">
<script>

function connect() {
    ws = new WebSocket('ws://127.0.0.1:6161');
    ws.onmessage = function (e) {
        console.log(e.data);
    };
    ws.timer = setInterval(function () {
        ws.send('ping');
    }, 50000);
    ws.onclose = function () {
        clearTimeout(ws.timer);
        setTimeout(connect, 1000);
    };
}

//  通过WebSocket连接将数据发送给服务端
function send() {
    ws.send($('#content').val());
    $('#content').val('');
}

connect();
</script>
</body>
</html>

用户手机浏览器端和电脑浏览器端代码类似。多个一个send函数,用来将数据发送给服务端。

快速测试

html代码里使用了jquery,请自行下载放置到本地。

终端运行 php start.php start -d,启动workerman的websocket服务。
终端运行 php -S 0.0.0.0:7171,这样利用php cli启动了一个webserver监听7171端口。

浏览器访问 http://127.0.0.1:7171/daping.html 和 http://127.0.0.1:7171/user.html

这样在user.html发送的文字会展示在 daping.html 上

如果页面访问超时,请在安全组或者防火墙没有放行6161 7171端口端口

更多推荐

git 常用命令总结

gitinit:初始化一个Git仓库。例:在项目目录下打开终端,输入gitinit即可将该目录初始化为Git仓库。gitadd:将文件添加到暂存区。例:将新添加的文件a.txt添加到暂存区,命令为gitadda.txt。gitcommit:将暂存区的文件提交到本地仓库。例:将暂存区的文件提交到本地仓库,并添加提交注释,

C语言文件的相关操作

C语言中文件的相关操作文件的打开使用文件的打开函数需要引入这个头文件:#include<fcntl.h>open函数intopen(charconst*pathname,intflags,mode_tmode)功能:打开已有的文件或者创建新文件参数pathname:文件路径名,可以是相对路径或绝对路径flags:打开文

[MIT6.824] Spring2021 Lab 2: Raft

0x1ReadingPaperRaft协议感觉目标很简单:保证分布式系统的一致性和可用性,在阅读时,我联想到之前看的ARIES论文,感觉思维有很多共通之处,比如如何通过非易失性存储来保证持久性。但是ARIES中是单个机器崩溃导致内存内容丢失,通过硬盘上的LOGs来重做数据库,并且ABORT掉未提交的记录并写入CLR。R

uni-app实现web-view图片长按下载

<template><view><web-view:webview-styles="webviewStyles":src="webUrl"></web-view></view></template>uniapp的web-view中图片无法长按保存,IOS下是正常的,但是Android下长按无反应解决方案:下载mui.m

什么是C语言中的命名空间?

C语言本身并没有像某些其他编程语言(如C++)中的显式命名空间(namespace)的概念,但C语言中有一些机制和约定,允许开发人员组织和管理变量、函数和其他标识符的名称,以避免名称冲突和提高代码可维护性。本文将介绍C语言中的命名空间概念,包括作用域、静态变量、文件作用域、函数作用域以及如何避免名称冲突。作用域(Sco

会C++还需要再去学Python吗?

提到的C++、数据结构与算法、操作系统、计算机网络和数据库技术等确实是计算机科学中非常重要的基础知识领域,对于软件开发和计算机工程师来说,它们是必备的核心知识。掌握这些知识对于开发高性能、可靠和安全的应用程序非常重要。Python作为一种脚本语言,在某些场景下确实可以作为加分项或辅助工具使用。它具有易学易用的特点,并且

【C++】泛型算法(六)Map和Set的使用

Mapmap<key,value>key起到索引的作用。//常见使用:字数统计程序#include<map>#include<string>map<string,int>words;//string是key,int是valuestringtword;while(cin>>tword){words[tword]++;//

解释器风格架构C# 代码

/*解释器风格架构是一种基于组件的设计架构,它将应用程序分解为一系列组件,每个组件负责处理特定的任务。这种架构有助于提高代码的可维护性和可扩展性。以下是如何使用C#实现解释器风格架构的步骤:定义组件:首先,定义一个组件接口,这将是所有组件需要遵循的规范。这包括组件的基本操作,如添加、删除、查询等。*/voidMain(

c#设计模式-结构型模式 之适配器模式

🚀介绍将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。适配器模式(Adapter)包含以下主要角色:目标(Target)接口

算力和LAXCUS分布式操作系统

有用户问LAXCUS分布式操作系统和算力的关系,今天借这个话题讲讲二者的关联。算力是指计算机系统在单位时间内所能完成的计算任务数量。随着计算机技术的发展,尤其是大数据、云计算、人工智能等新技术、新应用业务的出现,算力已经成为了衡量计算系统和产业业态的重要指标。在传统的集中式计算模式下,算力的提升主要依赖于硬件设备的升级

C语言每日一题(1):实现库函数strlen()

文章主题:库函数strlen()的实现所属专栏:C语言每日一题作者简介:每天不定时更新C语言的小白一枚,记录分享自己每日的所思所想。个人主页:[₽]的个人主页目录前言函数介绍编程起因设计思路1.整体逻辑2.参数类型3.防止空指针4.返回值代码展示结语前言函数介绍strlen()函数是我们在C语言编程中常用到库函数。在C

热文推荐