`
berrywu
  • 浏览: 128383 次
  • 性别: Icon_minigender_1
  • 来自: 福建
社区版块
存档分类
最新评论

PHP+Flex实现多人聊天之服务端(解决安全沙箱问题)

阅读更多

说明:

客户端在第一次请求service的时候,会事先发送安全信息请求验证,因此当你捕获到“policy-file-request”的时候,直接返回策略文件信息:"<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0"。此时,客户端会另外开一个连接请求service。这样就可以同过安全沙箱验证了。

跟踪service端信息:

2010-06-21 16:30:47 Listening on port 10000. Server started at 16:30:47
2010-06-21 16:30:54 New connection ( 0 ) from 192.168.17.55 on port 1872
2010-06-21 16:30:54 Received 'policy-file-request' from 0
2010-06-21 16:30:54 sending: "<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>" to: 0
2010-06-21 16:30:54 Closed connection ( 0 ) from 192.168.17.55 on port 1872
2010-06-21 16:30:54 New connection ( 0 ) from 192.168.17.55 on port 1873

代码如下:

<?PHP
/**
* patServer
* PHP socket server base class
* Events that can be handled:
*   * onStart
*   * onConnect
*   * onConnectionRefused
*   * onClose
*   * onShutdown
*   * onReceiveData
*
* @version 1.1
* @author   Stephan Schmidt <schst@php-tools.de>
* @package patServer
*/
class patServer{
    /**
* information about the project
* @var array $systemVars
*/
    var $systemVars   = array(

    "appName"   => "patServer",
    "appVersion"   => "1.1",
    "author"   => array("Stephan Schmidt <schst@php-tools.de>", )
    );

    /**
* port to listen
* @var integer   $port
*/
    var $port   = 10000;

    /**
* domain to bind to
* @var string $domain
*/
    var $domain   = "localhost";

    /**
* maximum amount of clients
* @var integer $maxClients
*/
    var $maxClients = -1;

    /**
* buffer size for socket_read
* @var integer $readBufferSize
*/
    var $readBufferSize   = 128;

    /**
* end character for socket_read
* @var integer $readEndCharacter
*/
    var $readEndCharacter = "\n";

    /**
* maximum of backlog in queue
* @var integer $maxQueue
*/
    var $maxQueue = 500;

    /**
* debug mode
* @var boolean $debug
*/
    var $debug   = true;

    /**
* debug mode
* @var string $debugMode
*/
    var $debugMode = "text";

    /**
* debug destination (filename or stdout)
* @var string $debugDest
*/
    var $debugDest = "stdout";

    /**
* empty array, used for socket_select
* @var array $null
*/
    var $null   = array();

    /**
* all file descriptors are stored here
* @var array $clientFD
*/
    var $clientFD = array();

    /**
* needed to store client information
* @var array $clientInfo
*/
    var $clientInfo = array();

    /**
* needed to store server information
* @var array $serverInfo
*/
    var $serverInfo = array();

    /**
* amount of clients
* @var integer   $clients
*/
    var $clients = 0;

    /**
* create a new socket server
*
* @access public
* @param string   $domain   domain to bind to
* @param integer   $port   port to listen to
*/
    function patServer( $domain = "localhost", $port = 8083 ){
        $this->domain = $domain;
        $this->port   = $port;

        $this->serverInfo["domain"]         = $domain;
        $this->serverInfo["port"]         = $port;
        $this->serverInfo["servername"]     = $this->systemVars["appName"];
        $this->serverInfo["serverversion"] = $this->systemVars["appVersion"];
//        $this->readEndCharacter = chr('0');

        set_time_limit( 0 );
    }

    /**
* set maximum amount of simultaneous connections
*
* @access public
* @param int $maxClients
*/
    function setMaxClients( $maxClients ){
        $this->maxClients = $maxClients;
    }

    /**
* set debug mode
*
* @access public
* @param mixed $debug [text|htmlfalse]
* @param string $dest destination of debug message (stdout to output or filename if log should be written)
*/
    function setDebugMode( $debug, $dest = "stdout" ){
        if( $debug === false ){
            $this->debug = false;
            return true;
        }

        $this->debug   = true;
        $this->debugMode = $debug;
        $this->debugDest = $dest;
    }

    /**
* start the server
*
* @access public
* @param int $maxClients
*/
    function start(){
        $this->initFD = @socket_create( AF_INET, SOCK_STREAM, 0 );
        if( !$this->initFD )
        die( "patServer: Could not create socket." );

        // adress may be reused
        socket_setopt( $this->initFD, SOL_SOCKET, SO_REUSEADDR, 1 );

        // bind the socket
        if( !@socket_bind( $this->initFD, $this->domain, $this->port ) ){
            @socket_close( $this->initFD );
            die( "patServer: Could not bind socket to ".$this->domain." on port ".$this->port." ( ".$this->getLastSocketError( $this->initFd )." )." );
        }

        // listen on selected port
        if( !@socket_listen( $this->initFD, $this->maxQueue ) )
        die( "patServer: Could not listen ( ".$this->getLastSocketError( $this->initFd )." )." );

        $this->sendDebugMessage( "Listening on port ".$this->port.". Server started at ".date( "H:i:s", time() ) );

        // this allows the shutdown function to check whether the server is already shut down
        $GLOBALS["_patServerStatus"] = "running";
        // this ensures that the server will be sutdown correctly
        register_shutdown_function( array( $this, "shutdown" ) );

        if( method_exists( $this, "onStart" ) )
        $this->onStart();

        $this->serverInfo["started"] = time();
        $this->serverInfo["status"]   = "running";

        while( true ){
            $readFDs = array();
            array_push( $readFDs, $this->initFD );

            // fetch all clients that are awaiting connections
            for( $i = 0; $i < count( $this->clientFD ); $i++ )
            if( isset( $this->clientFD[$i] ) )
            array_push( $readFDs, $this->clientFD[$i] );

            // block and wait for data or new connection
            $ready = @socket_select( $readFDs, $this->null, $this->null, NULL );

            if( $ready === false ){
                $this->sendDebugMessage( "socket_select failed." );
                $this->shutdown();
            }

            // check for new connection
            if( in_array( $this->initFD, $readFDs ) ){
                $newClient = $this->acceptConnection( $this->initFD );

                // check for maximum amount of connections
                if( $this->maxClients > 0 ){
                    if( $this->clients > $this->maxClients ){
                        $this->sendDebugMessage( "Too many connections." );

                        if( method_exists( $this, "onConnectionRefused" ) )
                        $this->onConnectionRefused( $newClient );

                        $this->closeConnection( $newClient );
                    }
                }

                if( --$ready <= 0 )
                continue;
            }

            // check all clients for incoming data
            for( $i = 0; $i < count( $this->clientFD ); $i++ ){
                if( !isset( $this->clientFD[$i] ) )
                continue;

                if( in_array( $this->clientFD[$i], $readFDs ) ){
                    $data = $this->readFromSocket( $i );

                    // empty data => connection was closed
                    if( !$data ){
                        $this->sendDebugMessage( "Connection closed by peer" );
                        $this->closeConnection( $i );
                    }else{
						if(strpos($data, 'cross-domain-policy'))
							$this->sendDebugMessage( "Received 'policy-file-request' from ".$i );
						else
							$this->sendDebugMessage( "Received ".trim( $data )." from ".$i );
                        if( method_exists( $this, "onReceiveData" ) )
                        $this->onReceiveData( $i, $data );
                        if (strpos($data, 'cross-domain-policy')) {
                            $this->closeConnection($i);
                        }
                    }
                }
            }
        }
    }

    /**
* read from a socket
*
* @access private
* @param integer $clientId internal id of the client to read from
* @return string $data   data that was read
*/
    function readFromSocket( $clientId ){
        // start with empty string
        $data   = "";

        // read data from socket
        while( $buf = socket_read( $this->clientFD[$clientId], $this->readBufferSize ) ){
            $data .= $buf;
            if(strpos($buf,'policy-file-request')){
                $data = "<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";
                break;
            }else {
                $endString = substr( $buf, - strlen( $this->readEndCharacter ) );
                if($this->readEndCharacter == $endString) {
                    break;
                }
                if( $buf == NULL )
                break;
            }
        }

        if( $buf === false )
        $this->sendDebugMessage( "Could not read from client ".$clientId." ( ".$this->getLastSocketError( $this->clientFD[$clientId] )." )." );
        return $data;
    }

    /**
* accept a new connection
*
* @access public
* @param resource &$socket socket that received the new connection
* @return int    $clientID internal ID of the client
*/
    function acceptConnection( &$socket ){
        for( $i = 0 ; $i <= count( $this->clientFD ); $i++ ){
            if( !isset( $this->clientFD[$i] ) || $this->clientFD[$i] == NULL ){
                $this->clientFD[$i] = socket_accept( $socket );
                socket_setopt( $this->clientFD[$i], SOL_SOCKET, SO_REUSEADDR, 1 );
                $peer_host = "";
                $peer_port = "";
                socket_getpeername( $this->clientFD[$i], $peer_host, $peer_port );
                $this->clientInfo[$i] = array(
                "host"   => $peer_host,
                "port"   => $peer_port,
                "connectOn" => time()
                );
                $this->clients++;

                $this->sendDebugMessage( "New connection ( ".$i." ) from ".$peer_host." on port ".$peer_port );

                if( method_exists( $this, "onConnect" ) )
                $this->onConnect( $i );
                return $i;
            }
        }
    }

    /**
* check, whether a client is still connected
*
* @access public
* @param integer $id client id
* @return boolean $connected true if client is connected, false otherwise
*/
    function isConnected( $id ){
        if( !isset( $this->clientFD[$id] ) )
        return false;
        return true;
    }

    /**
* close connection to a client
*
* @access public
* @param int $clientID internal ID of the client
*/
    function closeConnection( $id ){
        if( !isset( $this->clientFD[$id] ) )
        return false;

        if( method_exists( $this, "onClose" ) )
        $this->onClose( $id );

        $this->sendDebugMessage( "Closed connection ( ".$id." ) from ".$this->clientInfo[$id]["host"]." on port ".$this->clientInfo[$id]["port"] );

        @socket_close( $this->clientFD[$id] );
        $this->clientFD[$id] = NULL;
        unset( $this->clientInfo[$id] );
        $this->clients--;
    }

    /**
* shutdown server
*
* @access public
*/
    function shutDown(){
        if( $GLOBALS["_patServerStatus"] != "running" )
        exit;
        $GLOBALS["_patServerStatus"] = "stopped";

        if( method_exists( $this, "onShutdown" ) )
        $this->onShutdown();

        $maxFD = count( $this->clientFD );
        for( $i = 0; $i < $maxFD; $i++ )
        $this->closeConnection( $i );

        @socket_close( $this->initFD );

        $this->sendDebugMessage( "Shutdown server." );
        exit;
    }

    /**
* get current amount of clients
*
* @access public
* @return int $clients amount of clients
*/
    function getClients(){
        return $this->clients;
    }

    /**
* send data to a client
*
* @access public
* @param int   $clientId ID of the client
* @param string $data   data to send
* @param boolean $debugData flag to indicate whether data that is written to socket should also be sent as debug message
*/
    function sendData( $clientId, $data, $debugData = true ){
        if( !isset( $this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL )
        return false;

        if( $debugData )
        $this->sendDebugMessage( "sending: \"" . $data . "\" to: $clientId" );

        if( !@socket_write( $this->clientFD[$clientId], $data ) )
        $this->sendDebugMessage( "Could not write '".$data."' client ".$clientId." ( ".$this->getLastSocketError( $this->clientFD[$clientId] )." )." );
    }

    /**
* send data to all clients
*
* @access public
* @param string $data   data to send
* @param array $exclude client ids to exclude
*/
    function broadcastData( $data, $exclude = array(), $debugData = true ){
        if( !empty( $exclude ) && !is_array( $exclude ) )
        $exclude = array( $exclude );

        for( $i = 0; $i < count( $this->clientFD ); $i++ ){
            if( isset( $this->clientFD[$i] ) && $this->clientFD[$i] != NULL && !in_array( $i, $exclude ) ){
                if( $debugData )
                $this->sendDebugMessage( "sending: \"" . $data . "\" to: $i" );

                if( !@socket_write( $this->clientFD[$i], $data ) )
                $this->sendDebugMessage( "Could not write '".$data."' client ".$i." ( ".$this->getLastSocketError( $this->clientFD[$i] )." )." );
            }
        }
    }

    /**
* get current information about a client
*
* @access public
* @param int   $clientId ID of the client
* @return array $info   information about the client
*/
    function getClientInfo( $clientId ){
        if( !isset( $this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL )
        return false;
        return $this->clientInfo[$clientId];
    }

    /**
* send a debug message
*
* @access private
* @param string $msg message to debug
*/
    function sendDebugMessage( $msg ){
        if( !$this->debug )
        return false;

        $msg = date( "Y-m-d H:i:s", time() ) . " " . $msg;

        switch( $this->debugMode ){
            case "text":
                $msg = $msg."\n";
                break;
            case "html":
                $msg = htmlspecialchars( $msg ) . "<br />\n";
                break;
        }

        if( $this->debugDest == "stdout" || empty( $this->debugDest ) ){
            echo $msg;
            flush();
            return true;
        }

        error_log( $msg, 3, $this->debugDest );
        return true;
    }

    /**
* return string for last socket error
*
* @access public
* @return string $error last error
*/
    function getLastSocketError( &$fd ){
        $lastError = socket_last_error( $fd );
        return "msg: " . socket_strerror( $lastError ) . " / Code: ".$lastError;
    }
    function onReceiveData($ip,$data){
        $this->broadcastData( $data,array(), true );
    }
}
$patServer = new patServer('192.168.15.85','10000');
$patServer->start();
?>

 

分享到:
评论

相关推荐

    FLEX安全沙箱实用指南

    ### FLEX安全沙箱实用指南 #### 一、引言 在进行FLEX开发时,了解和掌握FLEX的安全沙箱机制对于确保应用程序的安全性至关重要。本文将详细介绍FLEX安全沙箱的相关概念及其应用场景,帮助开发者更好地理解如何在...

    ArcGIS API for Flex开发WebGIS中的安全沙箱问题

    在使用ArcGIS API for Flex开发WebGIS应用时,安全沙箱问题是一个重要的考虑因素,它涉及到数据的安全性和应用程序的跨域访问控制。Flex是Adobe Flash平台的一部分,用于创建丰富的互联网应用,而ArcGIS API for ...

    flex 安全沙箱 策略问题 demo

    在Adobe Flash Player升级到9.0.124后,由于安全策略更改,原来Socket或XmlSocket的应用里的http方式加载安全策略的...service_001是java服务端 connectbysocket 是flex客户端 connectbysocket请放在tomcat下试验效果

    Flash+Flex+AIR移动开发入门经典

    《Flash+Flex+AIR移动开发入门经典》是一本专为初学者设计的教程,全面讲解了使用Adobe的Flash、Flex和AIR技术进行移动应用开发的知识体系。这本书旨在帮助读者掌握如何利用这些强大的工具来创建跨平台的交互式应用...

    FLEX+Delphi,FLEX+Java,FLEX+C# 的聊天室

    客户端说明 chat.mxml socket.connect("127.0.0.1",8888);...FLEX+Java,FLEX+C#,FLEX+C++ &lt;br&gt;把swf放到网站上去,会出现安全沙箱问题没有解决,如果你解决了请告诉我(email:feng0904@163.com),谢谢

    Flex 安全沙箱问题 简单处理方法

    Flex安全沙箱问题是一个在开发基于...总的来说,解决Flex安全沙箱问题需要深入理解沙箱机制、跨域策略和`crossdomain.xml`文件的配置,同时关注服务器端的实现细节,以确保应用程序既能正常运行,又能保障用户的安全。

    NodeJS+Vue实现支付宝支付(沙箱)完整流程 .zip

    在本文中,我们将深入探讨如何使用NodeJS和Vue.js实现在沙箱环境中集成支付宝支付的完整流程。这个项目涉及的主要知识点包括NodeJS后端开发、Vue.js前端开发以及支付宝开放平台的API接口调用。 首先,我们需要理解...

    全面认识Flex安全沙箱

    Flex安全沙箱是Adobe Flex应用程序在运行时遵循的一套安全机制,旨在保护用户的数据和系统安全。这个概念是在Flex 4之后尤其受到关注,因为当时在Internet Explorer中出现了与安全沙箱相关的挑战。沙箱模型类似于...

    java和as3 socket通信 解决安全沙箱问题

    本文将深入探讨如何实现这两种语言间的Socket通信,并解决在Flash Player的安全沙箱问题。 首先,让我们理解什么是Socket通信。Socket是网络编程中的一个概念,它允许两个程序通过TCP/IP协议进行双向通信。在Java中...

    java ,c#,delphi 解决flash安全沙箱问题

    当我们面临“Java, C#, Delphi 解决 Flash 安全沙箱问题”的场景时,这意味着我们需要在这些编程语言中处理与 Flash 沙箱相关的安全问题,以确保应用程序的安全性和合规性。 首先,让我们深入了解一下 Flash 的安全...

    FLEX+Delphi+Java+C#联合打造聊天室

    FLEX+Delphi+Java+C#联合打造聊天室14220982这是一个综合实战的例子,它是用FLEX+Delphi、FLEX+Java、 FLEX+C#多种语言巧妙组合而打造的超强功能的聊天室。服务端代码基于JAVA技术...彻底解决了以往版本中的沙箱问题。

    源于FLEX中的安全沙箱问题

    【标题】:“源于FLEX中的安全沙箱问题” 【描述】:在FLASH PLAYER中,安全沙箱是一个关键的安全性组件,它将资源逻辑地分组,以限制各个FLASH应用程序能够执行的操作和访问的资源。安全沙箱确保了各应用程序与...

    在Flex中发布地图 程序报错 SecurityError: Error #2048: 安全沙箱冲突,只需要下载添加这个就可以

    网上的方法很多,我看了好多,但是就是不管用,我的情况是,在程序没发布时,直接运行没错误,但是当发布时,访问就错了,提示SecurityError: Error #2048: 安全沙箱冲突:http://localhost:8086/index.swf 不能从 ...

    flex 沙箱安全问题

    ### flex沙箱安全问题 #### 一、概述 在Flex应用程序开发过程中,远程对象(RemoteObject)服务常常被用于客户端与服务器之间的数据交互。但在实际应用中,由于跨域策略的限制,可能会遇到Error #2048这样的错误...

    FLEX+Delphi,FLEX+Java 的聊天室

    FLEX3 开发 ChatServer Delphi6 开发的服务端 Server java 开发的服务端 &lt;br&gt;其实可以做到FLEX+Delphi,FLEX+Java,FLEX+C#,FLEX+C++ &lt;br&gt;把swf放到网站上去,会出现安全沙箱问题没有解决,如果你解决了请...

    flash安全沙箱汇总

    Flash安全沙箱通过一系列规则来实现对代码行为的约束。例如,网络沙箱中的代码不能直接读取或写入本地文件,而本地沙箱中的代码则可以在获得用户许可后进行此类操作。此外,沙箱还控制了代码可以访问的网络资源,...

    SpringBoot+Vue支付宝沙箱支付

    本项目“SpringBoot+Vue支付宝沙箱支付”旨在教你如何在SpringBoot后端与Vue前端环境中实现支付宝的沙箱测试环境支付功能,从而在不涉及真实交易的情况下测试支付流程的完整性和安全性。 首先,我们需要了解什么是...

    ActionScript 3.0安全沙箱及相关问题资料

    《Flex与.NET基于Socket的网络连接 收藏 .txt》和《Flex flash_player9 沙箱安全解决方案.txt》可能讨论了Flex应用程序与.NET服务通过Socket通信时如何处理安全沙箱问题,以及在Flash Player 9中如何解决这些问题的...

    AS与java socket通讯解决安全沙箱

    为了解决安全沙箱问题,我们需要采取以下步骤: 1. **设置安全策略文件**:在服务器端,你需要创建一个XML格式的安全策略文件(crossdomain.xml),声明允许哪些来源的AS客户端进行Socket连接。这个文件需要放在...

Global site tag (gtag.js) - Google Analytics