php socket如何实现长链接

长链接是什么?php

 

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

长链接和短连接前端

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

其大概有以下的几种解释:web

  1. 所谓长链接指创建SOCKET链接后不论是否使用都保持链接,但安全性较差;所谓短链接指创建SOCKET链接后发送后接收完数据后立刻断开链接,通常银行都使用短链接redis

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

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

  4. 短链接:好比http的,只是链接、请求、关闭,过程时间较短,服务器如果一段时间内没有收到请求便可关闭链接。长链接:有些服务须要长时间链接到服务器,好比CMPP,通常须要本身作在线维持。后端

实现socket长链接api

每次咱们访问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\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);

?>

下面来提升下效率:

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

?>

相关文章
相关标签/搜索