2010-01-12 5 views
2

나는 최근에 PHP가 fsock * 기능을 가질뿐만 아니라 서버 자체를 만드는 기능도 있다는 것을 알게되었습니다. 나는 조금 실험하기로 결정했고, 이것을 생각해 냈다. 자, 문제는 accept_connection() (연결 대기 중이라는 사실 때문에)입니다. 해결책은 stream_set_blocking()을 사용하는 것으로 밝혀졌으며, 실제로 시도했지만 아무런 문제가 없습니다.PHP 소켓 accept_connection 교수형

나는라는 오류 메시지를 받고 있습니다 :

Warning: socket_set_blocking(): supplied resource is not a valid stream resource in /home/insomniaque/workspace/PHP Socket RAT/rat.class.php on line 68

내가 두 번째 연결, 그것은 것이라고 출력 데이터와 연결 할 때 accept_connection() 문제 이전 때문에 것을 알고있다. 사전에

<?php 
/* 
* Project: iRAT 
* 
* Created on Jan 11, 2010 
* Written by Insomniaque 
* 
*/ 

class rat 
{ 
    /** 
    * Holds the PHP socket handle for use within the class. 
    */ 
    private $socket; 

    /** 
    * Holds an array of all the spawned sockets (child sockets) that were 
    * created when a user connected to the server. 
    */ 
    private $spawns = array(); 

    /** 
    * Holds the maximum number of connections. 
    */ 
    private $maxconn; 

    /** 
    * Sets all of the variables required for the class and starts the socket. 
    * Then it'll start looping, connecting clients and running commands. 
    * 
    * @access public 
    * @param $port The port to bind. 
    * @param $maxconn The maximum number of client connections. 
    */ 
    public function __construct($port = 0, $maxconn = 1) 
    { 
     /** 
     * Check to see if the user has entered 0 as the port, and create a 
     * random port, if so. 
     */ 
     if($port == 0) 
      $this->port = rand(81, 8079); 
     else 
      $this->port = $port; 

     /** 
     * Save the maximum connection number. 
     */ 
     $this->maxconn = $maxconn; 

     /** 
     * Run our function to create the socket now. 
     */ 
     if(!$this->createSocket()) 
     { 
      echo "Failed creating or binding socket.\n"; 
      return false; 
     } 
     else 
     { 
      echo "Socket has been created and binded.\n"; 
     } 

     /** 
     * Turn non-blocking on so we can run multiple clients. 
     */ 
     socket_set_blocking($this->socket, 0); 

     echo "Starting the data receiving loop.\n"; 
     $this->startLoop(); 

     return true; 
    } 

    /** 
    * This function will create the socket for later use. 
    * 
    * @access private 
    * @return bool Returns true if the socket was created successfully, 
    *    returns false if there was an error. 
    */ 
    private function createSocket() 
    { 
     /** 
     * Create a socket of IPv4 type using the TCP gateway. 
     */ 
     $this->socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); 
     if(!$this->socket) 
      return false; 
     echo "Socket has been created.\n"; 

     /** 
     * Attempt to bind the socket to localhost:[port] 
     */ 
     do 
     { 
      if(!isset($i)) 
       $i++; 

      $port = $this->port; 
      $bind = socket_bind($this->socket, 0, $port); 

      if(!$bind) 
      { 
       $i++; 
       $this->port = rand(79, 8079); 
      } 
     } while(!$bind && $i <= 5); 

     if($i == 5) 
      return false; 
     echo "Port ".$this->port." has been binded to the RAT.\n"; 

     return true; 
    } 

    /** 
    * Start a loop running on our socket. We will check if we are getting 
    * data, accept connections and run any commands. When the connection 
    * is closed, we will return true. 
    * 
    * @access private 
    * @return bool Returns false if the socket can't be listened to. Otherwise 
    *    returns true when the socket is closed. 
    */ 
    private function startLoop() 
    { 
     if(socket_listen($this->socket, 3)) 
     { 
      while(true) 
      { 
       if(($newspawn = socket_accept($this->socket)) !== false) 
       { 
        $this->spawns[] = $newspawn; 
        echo "A new spawn has connected."; 
       } else 
        echo "No new socket"; 
       sleep(1000); 

       foreach($this->spawns as $key => $spawn) 
       { 
        $data = trim(socket_read($spawn, 1024)); 
        if(strlen($data) > 0) 
        { 
         if($data == "exit") 
         { 
          socket_close($spawn); 
          unset($this->spawns[$key]); 
          echo "Spawn killed.\n"; 
         } 
         if($data == "kill") 
         { 
          foreach($this->spawns as $key => $spawn) 
          { 
           socket_close($spawn); 
           unset($this->spawns[$key]); 
          } 
          socket_close($this->socket); 
          echo "Socket closed.\n"; 
          return true; 
         } 
         else 
         { 
          echo "Data: " . $data . "\n"; 
         } 
        } 
       } 
      } 
     } 
     else 
     { 
      echo "Failure receiving data.\n"; 
      return false; 
     } 
    } 
} 
?> 

감사합니다, 존

답변

3

socket_create()에 의해 생성되는 소켓 리소스에 대해 socket_set_blocking() 대신 socket_set_nonblock()을 사용하십시오.

socket_set_blocking()

은 (는 fopen) 또는 stream_socket_create()

편집의 결과처럼, (PHP-) 작동 스트림 stream_set_blocking()의 별칭입니다 : 당신은 또한 모두 새로운 연결을 처리하기 위해 socket_select() 또는 stream_select()을 사용할 수 있습니다 및 클라이언트 데이터 패킷, 예.

private function createSocket() 
{ 
    $this->socket = stream_socket_server('tcp://0.0.0.0:'.(int)$this->port, $errno, $errstr); 
    if(!$this->socket) { 
    $this->socket = null; 
    echo "stream_socket_server failed : $errstr ($errno)\n"; 
    return false; 
    } 
    echo "Port ".$this->port." has been bound to the RAT.\n"; 
    return true; 
} 

public function startLoop() { 
    if (is_null($this->socket)) { 
    return false; 
    } 

    $write = array(); $exception=array(); 
    while(!$this->shutdown) { 
    // stream_select() alters the array, so $read has to be re-constructed in each iteration somehow 
    $read = array_merge(array($this->socket), $this->spawns); 
    // you might want to check $exception as well 
    if (0!==stream_select($read, $write, $exception, 4)) { 
     // $now $read only contains those sockets, that will not block 
     // for fread/accept operations 
     foreach($read as $s) { 
     if ($s===$this->socket) { 
      $this->onAccept(); 
     } 
     else { 
      $this->onClientPacket($s); 
     } 
     } 
    } 
    } 
    $this->shutdown(); 
} 

클라이언트가 다음과 같은 두 가지 명령을 전송할 경우 유의하십시오.

$fp1 = stream_socket_client("tcp://localhost:81", $errno, $errstr, 30); 
fwrite($fp1, "1 blabla"); 
fwrite($fp1, "exit"); 

반드시 서버에 2 개의 개별 메시지가 표시되는 것은 아닙니다.

+0

'socket_set_blocking()'이'stream_set_blocking()'의 별명 이니까 –

+0

나는 아침 4 시경 느린 타이핑을하고 첫 단락 뒤에 "Save"를 누른다 ;-) – VolkerK

+0

좋아, 이걸 시도해 봤어. (내가 socket_set_blocking()'에 링크 된 것을 알았을 때 전환하기 전에 사용했던 것처럼) 다음과 같은 에러가 발생합니다 : 경고 : socket_accept() : 들어오는 연결을 수락 할 수 없습니다 [11] 홈/insomniaque/workspace/PHP 소켓 RAT/rat.class.php on line 133'. –

1

난 당신이 socket_set_blocking()와 함께 사용할 수있는 유효한 자원을 반환해야합니다 socket_create()에 반대 stream_socket_create()를 사용에 관심이있을 것이라고 생각합니다.

새로 만든 소켓에서 연결을 수락하려면 stream_socket_accept()을 사용해야합니다.

+0

나는이 모든 것을 바꿔서 시도해 보았습니다. (실수로 코드를 잃어 버렸습니다.) 새로운 클라이언트를 연결하려고 시도해도 클라이언트 하나가 연결될 수있었습니다. –

+0

@ 존 - while 루프에서'stream_socket_accept'에서 반환 된 스트림 리소스에'socket_set_blocking'을 삽입 해보십시오. –

+0

@cballou : http://paste2.org/p/606125 -'stream_set_blocking()'은 성공하면 TRUE를 반환하고 실패하면 FALSE를 반환합니다. –