page contents

php socket如何实现长连接

以下内容希望帮助到大家!

attachments-2020-05-DM81Wo4j5ebce6047b6fc.jpg

长连接是什么?

朋友们应该都见过很多在线聊天工具和网页在线聊天的工具。学校内有一种熟悉的功能,如果有人回复你了,网站会马上出现提示,此时你并没有刷新页面;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长连接。

其实例代码如下:

<?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\n";  

        }else{  

            $msg = socket_read($fd, 1024); 

  

            if($msg <= 0){  

                //close  

            }else{                 

                echo "on message, fd=$fd data=$msg\n";  

            }  

        }  

    } 

   

    //写入事件 

    foreach($ws as $fd){  

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

    }       

}while(true);

?>

下面来提高下效率:

<?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用于转发消息。

其代码如下所示:

<?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");

?>


attachments-2020-05-LDO6D1RV5ebce5de1d9d0.jpg

  • 发表于 2020-05-14 14:34
  • 阅读 ( 623 )
  • 分类:PHP开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1478 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章