Проблема с сокетами

74 views
Skip to first unread message

Chris

unread,
May 31, 2012, 7:39:39 AM5/31/12
to highload-php-ru
Имеем TCP сервер, на который подключается клиент из сети и сбрасывает
данные.


[code]

<?php
// PHP SOCKET SERVER
error_reporting(E_ERROR);
// Configuration variables
$host = "127.0.0.1";
$port = 4041;
$max = 20;
$client = array();

// No timeouts, flush content immediatly
set_time_limit(0);
ob_implicit_flush();

// Server functions
function rLog($msg){
$msg = "[".date('Y-m-d H:i:s')."] ".$msg;
print($msg."\n");

}
// Create socket
$sock = socket_create(AF_INET,SOCK_STREAM,0) or die("[".date('Y-m-d
H:i:s')."] Could not create socket\n");
// Bind to socket
socket_bind($sock,$host,$port) or die("[".date('Y-m-d H:i:s')."] Could
not bind to socket\n");
// Start listening
socket_listen($sock) or die("[".date('Y-m-d H:i:s')."] Could not set
up socket listener\n");

rLog("Server started at ".$host.":".$port);
// Server loop
while(true){
socket_set_block($sock);
// Setup clients listen socket for reading
$read[0] = $sock;
for($i = 0;$i<$max;$i++){
if($client[$i]['sock'] != null)
$read[$i+1] = $client[$i]
['sock'];
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,$write = NULL, $except =
NULL, $tv_sec = NULL);
// If a new connection is being made add it to the
clients array
if(in_array($sock,$read)){
for($i = 0;$i<$max;$i++){
if($client[$i]['sock']==null){
if(($client[$i]
['sock'] = socket_accept($sock))<0){

rLog("socket_accept() failed: ".socket_strerror($client[$i]['sock']));
}else{

rLog("Client #".$i." connected");
}
break;
}elseif($i == $max - 1){
rLog("Too many
clients");
}
}
if(--$ready <= 0)
continue;
}
for($i=0;$i<$max;$i++){
if(in_array($client[$i]['sock'],$read)){
$input = socket_read($client[$i]
['sock'],1024);
if($input==null){

unset($client[$i]);
}
$n = trim($input);
$com = split(" ",$n);

// И ВОТ ЗДЕСЬ НАЧИНАЕТСЯ ПРИКОЛ

написан обработчик простой, что если if($n=="DATAblalalala"){ }

и если вдруг

if ($n == ""){
socket_close($client[$i]['sock']);
unset($client[$i]['sock']);
rLog("Disconnected(2) client #".$i);
}

//////////////////////////////////////

if($n=="EXIT"){
if($client[$i]
['sock']!=null){
//
Disconnect requested

socket_close($client[$i]['sock']);

unset($client[$i]['sock']);

rLog("Disconnected(2) client #".$i);

for($p=0;$p<count($client);$p++){

socket_write($client[$p]['sock'],"DISC ".$i.chr(0));
}
if($i
== $adm){

$adm = -1;
}
}
}elseif($n=="TERM"){
// Server
termination requested

socket_close($sock);
rLog("Terminated
server (requested by client #".$i.")");
exit();
}elseif($input){
// Strip
whitespaces and write back to user
// Respond to
commands
/*$output =
ereg_replace("[ \t\n\r]","",$input).chr(0);

socket_write($client[$i]['sock'],$output);*/
if($n=="PING"){

socket_write($client[$i]['sock'],"PONG".chr(0));
}
if($n=="<policy-
file-request/>"){

rLog("Client #".$i." requested a policy file...");

socket_write($client[$i]['sock'],$cdmp.chr(0));

socket_close($client[$i]['sock']);

unset($client[$i]);

$cdmp="";
}
}
}else{
//if($client[$i]['sock']!=null)
{
// Close the
socket
//
socket_close($client[$i]['sock']);
//
unset($client[$i]);
//
rLog("Disconnected(1) client #".$i);
//}
}
}
}
// Close the master sockets
socket_close($sock);
?>

[/code]


И вот наступает данный момент когда клиент присылает нулевую строку и
рвет САМ связь, вперед чем сервер... После этого сервер начинает
загружать на 100% CPU... и перестает принимать коннекты:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

При этом если зайти и самому написать exit, не прерывая соединение со
своей стороны, то всё продолжает работать замечательно.

Подскажите как можно эту ситуацию победить... Гугл облазил, пока
вариантов решения не нашел. Если 5.3 то ни на что не жалуется, если
5.4 жалуется на:


$ready = socket_select($read,$write = NULL, $except = NULL, $tv_sec =
NULL);


и на

socket_close($client[$i]['sock']);
unset($client[$i]['sock']);
rLog("Disconnected(2) client #".$i);


Из ошибок

Warning: socket_close() expects parameter 1 to be resource, null given

Кирилл Гарбар

unread,
May 31, 2012, 8:31:01 AM5/31/12
to highloa...@googlegroups.com
Ого....

А не проще было взять что-то более менее адекватное?

https://github.com/kakserpom/phpdaemon

Посмотри, может проще переписать на евентах?
--
Best Regards, Kirill Garbar

Phone: +44 75 009 26 199
ICQ: 307099
http://www.inteliec.eu

Sergey Golovashov

unread,
May 31, 2012, 8:38:05 AM5/31/12
to highloa...@googlegroups.com
Может проще :-) Рад буду любой подсказке! Сейчас буду смотреть что там предлагают.

Что такое евента? (извините за глупый вопрос)

2012/5/31 Кирилл Гарбар <ite...@gmail.com>



--
С уважением, Сергей С. Головашов

Кирилл Гарбар

unread,
May 31, 2012, 8:41:09 AM5/31/12
to highloa...@googlegroups.com
phpdaemon посмотрен на событиях. И события можно программисть самостоятельно. Там есть пример tcp сервера. Чутка исправить, и будет работать для вашего случая.

Sergey Golovashov

unread,
May 31, 2012, 8:42:20 AM5/31/12
to highloa...@googlegroups.com
Ох, теперь будет вопрос ещё глупее... Нашел вот:

<?php

/**
* @package NetworkServers
* @subpackage TelnetHoneypot
*
* @author Zorin Vasily <kak.serpom...@gmail.com>
*/
class TelnetHoneypot extends NetworkServer {
/**
* Setting default config options
* Overriden from ConnectionPool::getConfigDefaults
* @return array|false
*/
protected function getConfigDefaults() {
return array(
// @todo add description strings
'listen' => '0.0.0.0',
'listen-port' => 23,
);
}
}

class TelnetHoneypotConnection extends Connection {
/**
* Called when new data received.
* @param string New data.
* @return void
*/
public function stdin($buf) {
$this->buf .= $buf;
$finish =
(strpos($this->buf, $s = "\xff\xf4\xff\xfd\x06") !== FALSE)
|| (strpos($this->buf, $s = "\xff\xec") !== FALSE)
|| (strpos($this->buf, $s = "\x03") !== FALSE)
|| (strpos($this->buf, $s = "\x04") !== FALSE);

while (($line = $this->gets()) !== FALSE) {
$e = explode(' ', rtrim($line, "\r\n"), 2);
$cmd = trim($e[0]);

if ($cmd === 'ping') {
$this->writeln('pong');
}
elseif (
($cmd === 'exit')
|| ($cmd === 'quit')
) {
$this->writeln('Quit');
$this->finish();
} else {
$this->writeln('Unknown command "' . $cmd . '"');
}
}

if (
(strlen($this->buf) > 1024)
|| $finish
) {
$this->finish();
}
}
}

?>

Как мне с этим классом теперь работать? Как его запустить, чтобы поднялся сокет? Как понимаю дальше в классе
class TelnetHoneypotConnection extends Connection 

он исполнит всё, что напишу, это уже проще...

2012/5/31 Кирилл Гарбар <ite...@gmail.com>

Sergey Golovashov

unread,
May 31, 2012, 8:47:48 AM5/31/12
to highloa...@googlegroups.com
Спасибо! Буду изучать!

2012/5/31 Кирилл Гарбар <ite...@gmail.com>

Sergey Golovashov

unread,
Jun 2, 2012, 10:50:20 AM6/2/12
to highloa...@googlegroups.com

Мужики! Нашел в чем проблема... не решаемая.. возникает именно при разрыве связи клиентом. Избежать просто! Юзайте в сетевых вещах xinetd

31.05.2012 16:47 пользователь "Sergey Golovashov" <gl.chris...@gmail.com> написал:

Кирилл Гарбар

unread,
Jun 2, 2012, 3:49:31 PM6/2/12
to highloa...@googlegroups.com
Не пиши сюда больше :-(

2012/6/2 Sergey Golovashov <gl.chris...@gmail.com>
Reply all
Reply to author
Forward
0 new messages