socket + pcntl_fork 实现客户端请求,服务器实时监听返回处理 消息推送

<?php
    /*
        socket链接整个过程
        1,socket_create
        第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;
        第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部);
        第三个参数指定应用程序所使用的通信协议。此参数可以指定单个协议系列中的不同传输协议。在Internet通讯域中,此参数一般取值为0,系统会根据套接字的类型决定应使用的传输层协议。
        2,socket_connect
        3,socket_write
        4,socket_read
        5,socket_close
    */
    Class Client {
        static private $socket = null;

        public function __construct() {
            //不报错
            error_reporting(0);
            //引入数据库
            require_once('conn.php');
            if(self::$socket == null) 
                self::$socket = socket_create(AF_INET,SOCK_STREAM,0);
            if(self::$socket === false)
                exit('create socket fail! please check it!' . $this->err());
        }

        //连接并发送数据
        public function conn($ip,$port,$data) {
            //数组数据序列号保存发送
            $data = serialize($data);
            if(!socket_connect(self::$socket,$ip,$port))
                exit('socket connect error!' . $this->err());
            if(socket_write(self::$socket,$data) === false)
                exit('socket write error!' . $this->err());
        }

        //获取数据
        public function getBack() {
            $res = socket_read(self::$socket,4096);
            if($res === false)
                exit('socket read error !' . $this->err());
            if($res)
                return $res;
            else 
                return 'nothing return';
        }

        //析构释放资源
        public function __destruct() {
            socket_close(self::$socket);
        }

        //错误
        private function err() {
            return socket_strerror(socket_last_error());
        }
    }

 

 

<?php
    /*
        socket 服务器通信整个过程
        socket_creat
        socket_bind
        socket_listen
        socket_accetp
        socket_read
        socket_write
        socket_close

        注:1,服务器需要开启php 的pcntl系列扩展,
            2,服务器必须开通对应端口,而且需跟客户端请求端口一致
    */
    //监听客户端触发,
    class Message {
        private $socket     = null;

        public function __construct($info) {
            $this->init($info);
            //子程序结束后,系统自动回收,避免产生僵尸进程
            pcntl_signal(SIGCLD, SIG_IGN);
            pcntl_signal(SIGCHLD,SIG_IGN);
            //dojob
            $this->doJob();
        }

        //初始化
        private function init($info) {
            //创建通信
            if(!$this->socket = socket_create(AF_INET,SOCK_STREAM,0)) 
                exit('error: create fail!' . $this->err());
            //绑定端口
            if(!socket_bind($this->socket,$info['ip'],$info['port']))
                exit('error: bind fail' . $this->err());
            //监听端口
            if(!socket_listen($this->socket))
                exit('error: listen fail' . $this->err());
        }

        //处理数据
        public function doJob() {
            do{
                //接受一个通信
                $mes_sock     = socket_accept($this->socket);
                if($mes_sock === false)
                    exit('error: accept fail!' . $this->err());

                //读取到客户端传送过来的数据
                $mes_client = socket_read($mes_sock,4096);
                if($mes_client === false)
                    exit('error: read fail' . $this->err());
                $data         = unserialize($mes_client);

                //开始分进程
                $pid         = pcntl_fork();
                if($pid) {

                    //父进程
                    $remeg             = '';
                    if($data['type'] == 1) 
                        $remeg         = 'request ok!';
                    else 
                        $remeg         = 'allow ok!';

                    //将消息返回
                    if(socket_write($mes_sock,$remeg) === false)
                        exit('error: write fail' . $this->err());
                }else {
                    require_once('Db.class.php');
                    $conn             = Db::getInstance(array('ip'=>'192.168.1.11','user'=>'root','pass'=>'123456','database'=>'test'));
                    //子进程
                    if($data['type'] == 1) {
                        //处理用户申请加入圈子,当消息发送成功后,更改数据库信息
                        echo "处理用户申请加入圈子\n";
                        //$sql ="UPDATE test_add SET status = 1 WHERE status  ";
                        die;
                    }else{
                        //处理圈主审核
                        echo "处理圈主审核\n";
                        die;
                    }
                }

                //释放资源
                socket_close($mes_sock);
            }while(1);
        }


        //错误
        private function err() {
            return socket_strerror(socket_last_error());
        }

        //析构释放
        public function __desctruct() {
            socket_close($this->socket);
        }
    }

    //运行
    $message     = new Message(array('ip'=>'192.168.1.6','port'=>'1935'));

 

//附属的db类

<?php
    /*
        数据库类
    */
    class Db {
        //用于存放实例化的对象
        static private $_instance = null;

        //公共静态方法获取实例化的对象
        static protected function getInstance($data) {
            if (!(self::$_instance instanceof self)) {
                self::$_instance = new self($data);
            }
            return self::$_instance;
        }
        
        //私有克隆
        private function __clone() {}
        
        //私有构造
        private function __construct($data) {
            $conn             = mysql_connect($data['ip'],$data['user'],$data['pass']);
            if(!$conn)
                exit('数据库连接错误!' . mysql_error());
            mysql_query('set names utf8');
            mysql_query('use '. $data['database']);
        }

    }

 

可以实现客户端请求后,服务器立马返回数据,通知客户端请求成功。再子进程处理。而且不会有defunct僵尸进程。

posted @ 2014-08-06 18:18  栋的博客  阅读(506)  评论(0编辑  收藏  举报
深入理解php php扩展开发 docker mongodb