我最近发现PHP不仅具有fsock *功能,还具有创建服务器本身的功能。我决定尝试一下,然后想出来。现在,问题是它挂起accept_connection()
(由于它正在等待连接。)我发现解决方案是使用stream_set_blocking()
,正如您所看到的,我尝试过,但无济于事。
我收到一条错误消息,内容如下:
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;
}
}
}
?>
提前致谢, 约翰
答案 0 :(得分:3)
对socket_set_nonblock()创建的套接字资源使用socket_create()而不是socket_set_blocking()。
socket_set_blocking()是别名 stream_set_blocking()仅适用于(php-)流,例如fopen()或stream_socket_create()
的结果编辑:您还可以使用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");
这并不一定意味着您的服务器会收到两条不同的消息。
答案 1 :(得分:1)
我相信您会对使用stream_socket_create()而不是socket_create()
感兴趣,socket_set_blocking()
应返回与{{1}}一起使用的有效资源。
请注意,您还需要利用stream_socket_accept()开始接受新创建的套接字上的连接。