zoukankan      html  css  js  c++  java
  • php socket如何实现长连接

    长连接是什么?

    朋友们应该都见过很多在线聊天工具和网页在线聊天的工具。学校内有一种熟悉的功能,如果有人回复你了,网站会马上出现提示,此时你并没有刷新页面;Gmail也有此功能,如果邮箱里收到了新的邮件,网站会马上提醒你,即使你的网页一直未刷新过。说到这里大家肯定不陌生,就是复用一个链接持续不断的进行数据交互。在现下很多互联网业务场景都需要长连接的支持,比如:游戏、聊天、信息推送等等等,这么多类似的功能都离不开长连接。前一章节介绍了php socket通信,本章来介绍一下php socket长连接。

    长连接和短链接

    短连接一般都是单项请求数据,服务器不能主动把数据“推”想客户端,但有了长连接就好多了,利用后端与前端的技术组合起来,可以实现服务器的“推送信息”功能,如果数据库里面有更新,后端程序可以立即把数据“推送出来”,而不要多次反复请求,多次建立连接,多次断开。

    其大概有如下的几种解释:

    1. 所谓长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差;所谓短连接指建立SOCKET连接后发送后接收完数据后马上断开连接,一般银行都使用短连接

    2. 长连接就是指在基于tcp的通讯中,一直保持连接,不管当前是否发送或者接收数据。而短连接就是只有在有数据传输的时候才进行连接,客户-服务器通信/传输数据完毕就关闭连接。

    3. 通信方式 
      各网元之间共有两种连接方式:长连接和短连接。所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需 要双方发检测包以维持此连接。短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,即每次TCP连接只完成一对 CMPP消息的发送。 
      现阶段,要求ISMG之间必须采用长连接的通信方式,建议SP与ISMG之间采用长连接的通信方式。

    4. 短连接:比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。长连接:有些服务需要长时间连接到服务器,比如CMPP,一般需要自己做在线维持。

    实现socket长连接

    每次我们访问PHP脚本的时候,都是当所有的PHP脚本执行完成后,我们才得到返回结果。如果我们需要一个脚本持续的运行,那么我们就要通过php长连接的方式,来达到运行目的。

    想要玩长连接就需要跟socket打交道,socket的封装自然是少不的了。下面就通过代码来进行socket长连接。

    其实例代码如下:

    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

    <?php

    $sfd = socket_create(AF_INET, SOCK_STREAM, 0); 

    socket_bind($sfd, "0.0.0.0", 1234); 

    socket_listen($sfd, 511); 

    socket_set_option($sfd, SOL_SOCKET, SO_REUSEADDR, 1); 

    socket_set_nonblock($sfd); 

    $rfds = array($sfd); 

    $wfds = array();

      

    do

        $rs = $rfds

        $ws = $wfds

        $es = array(); 

        $ret = socket_select($rs, $ws, $es, 3);       

        //读取事件

        foreach($rs as $fd){ 

            if($fd == $sfd){

               $cfd = socket_accept($sfd); 

               socket_set_nonblock($cfd); 

                $rfds[] = $cfd

                echo "new client coming, fd=$cfd "

            }else

                $msg = socket_read($fd, 1024);

      

                if($msg <= 0){ 

                    //close 

                }else{                

                    echo "on message, fd=$fd data=$msg "

                

            

        }

       

        //写入事件

        foreach($ws as $fd){ 

            socket_write($fd, ........); 

        }      

    }while(true);

    ?>

    下面来提高下效率:

    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

    <?php

    $sfd = stream_socket_server ('tcp://0.0.0.0:1234', $errno, $errstr); 

    stream_set_blocking($sfd, 0); 

    $base = event_base_new(); 

    $event = event_new(); 

    event_set($event, $sfd, EV_READ | EV_PERSIST, 'ev_accept', $base); 

    event_base_set($event, $base); 

    event_add($event); 

    event_base_loop($base);

      

    function ev_accept($socket, $flag, $base

        $connection = stream_socket_accept($socket); 

        stream_set_blocking($connection, 0); 

        $buffer = event_buffer_new($connection, 'ev_read', NULL, 'ev_error'$connection);     

        event_buffer_base_set($buffer, $base); 

        event_buffer_timeout_set($buffer, 30, 30); 

        event_buffer_watermark_set($buffer, EV_READ, 0, 0xffffff); 

        event_buffer_priority_set($buffer, 10); 

        event_buffer_enable($buffer, EV_READ | EV_PERSIST); 

    }

      

    function ev_error($buffer, $error, $connection

        event_buffer_disable($buffer, EV_READ | EV_WRITE);                 

        event_buffer_free($buffer);                 

        fclose($connection);                 

    }

      

    function ev_read($buffer, $connection

        $read = event_buffer_read($buffer, 256); 

        //do something.... 

    }

    ?>

    随着人数的增长,并发的提升,单个进程已经满足不了需求了,现成的就有扩展和库来解决这个事,比如:swoole,workerman等?但是,我们在使用php来开发web的时候,也没有使用webserver相关的库来做开发对不对?咱只是简单的echo而已。这些繁杂的事都交给了nginx或者是apache,是他们义无反顾的顶在前面,让我们可以专心写逻辑。写socket服务不比写web高级,都是打码,都是完成需求,通信那层都是固定的,只不过一个由nginx完成,另一个由自己完成。。可是现在不需要自己完成了,类似nginx+fpm的方案,fooking+fpm=php长连接,gateway用于承载连接,router用于转发消息。

    其代码如下所示:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    <?php

    $sid = $_SERVER['SESSIONID'];//这是sessionid 

    $data = file_get_contents("php://input");//这样就能拿到请求内容了 

    //想要返回消息只需要两步 

    header('Content-Length: 11');//返回给客户端字节数 

    echo "hello world"

    //想要给别的用户发消息 

    include 'api.php'

    $router = new RouterClient('router host', 'router port'); 

    $router->sendMsg(用户sessionid, "fuck you"); 

    //想要给所有人要消息 

    $router->sendAllMsg("fuck all"); 

    //想给指定组发消息(类似redis的pub/sub) 

    $router->publish("channel name", "fuck all");

    ?>

  • 相关阅读:
    解决laravel 429请求错误
    laravel的Validation检索验证错误消息
    Laravel通过用户名和密码查询
    Javascript 利用 switch 语句进行范围判断
    解决SourceTree每次拉取提交都需要输入密码的问题
    nginx ip配置反向代理为本地域名
    Linux top命令详解
    《Inside C#》笔记(六) 属性、数组、索引器
    《Inside C#》笔记(五) 方法
    《Inside C#》笔记(四) 类
  • 原文地址:https://www.cnblogs.com/bluealine/p/11038782.html
Copyright © 2011-2022 走看看