Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   PHP, PERL, MySQL, JavaScript (https://forum.antichat.xyz/forumdisplay.php?f=37)
-   -   Jabber бот на php - проблема с сокетами (https://forum.antichat.xyz/showthread.php?t=113247)

Krist_ALL 27.03.2009 14:21

Jabber бот на php - проблема с сокетами
 
Всем привет!
Решил написать своего джаббер бота на пхп. Не нада кричать что есть готовые бибоиотеки с xmpp итд, я пишу с нуля. Проблема заключается втом, что функция socket_read читает только один пакет, их бывает приходит 2 или 3, приходится ее писать несколько раз, из-за этого (я так думаю, но не факт что это из-за функции) у меня сбивается порядок огбмена пакеами и соединение рвется что-ли... посылаю данные а ответа не вижу (еслиб я допустил ошибку в формировании данных, пришел бы пакет, говорящий об ошибке в синтаксисе) .. Помогите плз.


PHP код:

<?php 
$JABBER_SERVER 
"jabber.ru"
$PORT 5222
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP); 
if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }  
 
$connect socket_connect($socket$JABBER_SERVER$PORT);
 if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }  

$t "<stream:stream to='jabber.ru' xmlns='jabber:client' "$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/>";
 echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>'
socket_write($socket$t); 

$data socket_read($socket5000);
echo 
'<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>"

$data socket_read($socket5000); 

echo 
'<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>";  

$data socket_read($socket5000); echo '<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>";  

$t1 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />"

echo 
'<b>Клиент - </b>'.htmlspecialchars($t1).'<br><br>'

socket_write($socket$t1); $data socket_read($socket5000); 

echo 
'<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>";    

//socket_close($socket); 

?>


Krist_ALL 27.03.2009 17:01

На многих форумах по пхп мне не помогли. Не знают как сделать...

Вя надежда на вас!

Pashkela 27.03.2009 17:32

попробуй так:

1. $t = блаблабалбала и в конце всегда ."\n";

2. Явно указать длину того, чего пишешь:

socket_write($socket, $t, strlen($t));


3. Читать можно попробовать так:

socket_read($socket, 5000, PHP_NORMAL_READ);


А вообще читай:

http://ru.php.net/socket_read

там есть примеры работы с сокетами, правильные примеры

Krist_ALL 27.03.2009 17:49

Warning: socket_read() [function.socket-read]: unable to read from socket [104]: Connection reset by peer in ....

Сделал как сказал Pashkela но вот такая штука вылезла.....

KaZ@NoVa 27.03.2009 18:26

ты под каким Php этот код писал. У меня ошибку пишет, что функции socket_create не существует.
И я не пойму, что означают строки вида:
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />

Krist_ALL 27.03.2009 18:34

Плд нормальным! ВОт под каким ты запускаещь скриепт я непойму

laedafess 27.03.2009 19:10

Цитата:

Сообщение от KaZ@NoVa
ты под каким Php этот код писал. У меня ошибку пишет, что функции socket_create не существует.

в пхп надо php_sockets.dll добавить

Gifts 27.03.2009 19:11

Krist_ALL Примерный план подключение к джаббер серверу:

1) Создаем сокет (socket_create)
2) Подключаемся к серверу(socket_connect)
3) Посылаем инициализирующий запрос (<?xml version='1.0'?><stream:stream to=' и т.д.)
4) А вот дальше нужен цикл обработки и собственно ответов. Приблизительного вида:
PHP код:

// $sock - первоначальный сокет от socket_create
while (1)
{
    
$read=array($sock);
    
$count=socket_select($read,$write=null,$exception=null,15);
    
// Если ничего не пришло пропускаем
    // Или если нужно что то послать по собственному желанию - отправляем
    
if ($count<1) continue; 
    
    foreach (
$read as $one)
      {
        
$input=socket_read($one,4096);
        
// Тут обработка принятого пакета
        // например если пришел пакет  stream features ответить пакетом начала SASL авторизации
      
}


Сам сейчас осваиваю питон и тоже пишу свой клиент джаббера

З.Ы. Ох и намучаешься ты с DIGEST-MD5 ))

Pashkela Не вводите людей в заблуждение, если вы не разбираетесь. XMPP не предусматривает символ перевода строк, чтобы можно было читать NORMAL_READ и для socket_write НЕ требуется указывать длину буфера, если конечно не хочется передавать обрезанные данные

Krist_ALL 27.03.2009 19:43

Gifts, сделал я как ты написал, но чет скрипт зависв браузере - полаеися бесконечный цикл же вайл

PHP код:

<?php 
$JABBER_SERVER 
"jabber.ru"
$PORT 5222;  

$socket socket_create(AF_INETSOCK_STREAMSOL_TCP); 

if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }  

$connect socket_connect($socket$JABBER_SERVER$PORT); 

if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }   

$t "<stream:stream to='jabber.ru' xmlns='jabber:client' "
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/> ";  

echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>'

socket_write($socket$t);   



while (
1)  {      


$read=array($socket);      
$count=socket_select($read,$write=null,$exception=  null,15);      
// Если ничего не пришло пропускаем      
// Или если нужно что то послать по собственному желанию - отправляем      

if ($count<1) continue;             
foreach (
$read as $one)     
{        
$input=socket_read($one,4096);          
echo 
"htmlspecialchars($input)";         
// Тут обработка принятого пакета          
// например если пришел пакет  stream features ответить пакетом начала SASL авторизации          //

echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";       
}  
}
?>

НА счет типа авторизации - эт канешно сложно, но я выдерну какнить из класса готового.. ПРосто я хочу нааписать своего бота а не готового юзать.

Gifts 27.03.2009 19:48

Krist_ALL Естественно "завис". Клиент принял пакет и в бесконечном цикле ждет, когда придет следующий, а в браузер ничего не выводится из-за буферизации вывода.

Сделай так:
PHP код:

<?php 
$JABBER_SERVER 
"jabber.ru"
$PORT 5222;  
$i=0;

$socket socket_create(AF_INETSOCK_STREAMSOL_TCP); 

if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }  

$connect socket_connect($socket$JABBER_SERVER$PORT); 

if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }   

$t "<stream:stream to='jabber.ru' xmlns='jabber:client' "
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/> ";  

echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>'

socket_write($socket$t);   



while (
1)  {      


$read=array($socket);      
$count=socket_select($read,$write=null,$exceptionnull,1);      
// Если ничего не пришло пропускаем      
// Или если нужно что то послать по собственному желанию - отправляем      
if ($i++ > 5) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов
if ($count<1) continue;             
foreach (
$read as $one)     
{        
$input=socket_read($one,4096);          
echo 
"htmlspecialchars($input)";         
// Тут обработка принятого пакета          
// например если пришел пакет  stream features ответить пакетом начала SASL авторизации          //

echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";       
}  
}
?>


Krist_ALL 27.03.2009 20:03

Ну вот опять тажа проблема, что и вначале - немогу послать второй пакет, тоестья его ослал но ответа не вижу


PHP код:


<?php    
$JABBER_SERVER 
"jabber.ru";    
$PORT 5222;     
$i=0;     
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP);      
if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }       

$connect socket_connect($socket$JABBER_SERVER$PORT);      

if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }        





$t "<stream:stream to='jabber.ru' xmlns='jabber:client' ";    
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/> ";       

echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>';      

socket_write($socket$t);            


while (
1)  {             
$read=array($socket);         
$count=socket_select($read,$write=null,$exception=   null,1);         
// Если ничего не пришло пропускаем        
// Или если нужно что то послать по собственному желанию - отправляем         
if ($i++ > 5) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов   

if ($count<1) continue;                

foreach (
$read as $one)        {           $input=socket_read($one,4096);                 
// Тут обработка принятого пакета             
// например если пришел пакет  stream features ответить пакетом начала SASL авторизации          
 
echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";          

}     
}     



$t2 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />";  

echo 
'<b>Клиент - </b>'.htmlspecialchars($t2).'<br><br>';        
socket_write($socket$t2);            

while (
1)  {             $read=array($socket);         $count=socket_select($read,$write=null,$exception=   null,1);         

// Если ничего не пришло пропускаем         
// Или если нужно что то послать по собственному желанию - отправляем         
if ($i++ > 5) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов   

if ($count<1) continue;                foreach ($read as $one)        {           $input=socket_read($one,4096);                  
// Тут обработка принятого пакета             
// например если пришел пакет  stream features ответить пакетом начала SASL авторизации          

echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";       
   }    
 }                                         
  
?>

Вот что выводтся в браузере

Цитата:


socket open - OK
socket connect - OK
Клиент - <stream:stream to='jabber.ru' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/>

Ответ от jabber - <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='2125564970' from='jabber.ru' version='1.0' xml:lang='en'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><compression xmlns='http://jabber.org/features/compress'><method>zlib</method></compression><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism></mechanisms><register xmlns='http://jabber.org/features/iq-register'/></stream:features></stream:stream>

Ответ от jabber -
Ответ от jabber -
Ответ от jabber -
Ответ от jabber -
Ответ от jabber -

Клиент - <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />


Pashkela 27.03.2009 20:18

/* Allow the script to hang around waiting for connections. */
set_time_limit(0);

/* Turn on implicit output flushing so we see what we're getting
* as it comes in. */
ob_implicit_flush();

Krist_ALL 27.03.2009 20:38

ПРичем тут ob_implicit_flush();...
В холостую идет чтение опять......

Gifts 27.03.2009 20:50

Krist_ALL Господи, что Вы делаете. Цикл обработки будет один! не надо его копипастить сто тыщ раз. Я специально комментарий оставил где должна быть обработка. Объясняю, на том месте должно быть что-то вроде:
PHP код:

if (strpos($input,'stream:features')!==false)
{
отправить пакет на запрос SASL авторизации


И второе - почитайте спецификацию. НЕЛЬЗЯ закрывать тэг <stream:stream> если вы не хотите закрыть соединение. Ака:
PHP код:

$t "<stream:stream to='jabber.ru' xmlns='jabber:client' ";    
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/> "

"/>" Считается закрытием тэга. Уберите слеш

Pashkela 27.03.2009 20:51

PHP код:

<?php     
/* Allow the script to hang around waiting for connections. */
set_time_limit(0);
@
ini_set("display_errors","1");

/* Turn on implicit output flushing so we see what we're getting
* as it comes in. */
ob_implicit_flush();

$JABBER_SERVER "jabber.ru";     
$PORT 5222;      
$i=0;      
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP);       
if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }        

$connect socket_connect($socket$JABBER_SERVER$PORT);       

if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }         





$t "<stream:stream to='jabber.ru' xmlns='jabber:client' ";     
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'/> ";        

echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>';       

socket_write($socket$t);             


while (
1)  {              
   
$read=array($socket);          
   
$count=socket_select($read,$write=null,$exception=     null,1);          
   
// Если ничего не пришло пропускаем         
   // Или если нужно что то послать по собственному желанию - отправляем          
   
if ($i++ > 5) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов    
   
if ($count<1) continue;                 
   foreach (
$read as $one) {                  
       
$input=socket_read($one,4096);                  
       if (!empty(
$input)) {
             
// Тут обработка принятого пакета              
            // например если пришел пакет  stream features ответить пакетом начала SASL авторизации           
            
echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";           

       }      
   }      
}


$t2 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />";   

echo 
'<b>Клиент - </b>'.htmlspecialchars($t2).'<br><br>';         
socket_write($socket$t2);             

while (
1)  {             $read=array($socket);         $count=socket_select($read,$write=null,$exception=     null,1);          

// Если ничего не пришло пропускаем          
// Или если нужно что то послать по собственному желанию - отправляем          
if ($i++ > 5) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов    

if ($count<1) continue;                foreach ($read as $one)        {           $input=socket_read($one,4096);

if (!empty(
$input)) {                   
// Тут обработка принятого пакета              
// например если пришел пакет  stream features ответить пакетом начала SASL авторизации           

echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";        
 }  
 }     
 }                                          
  
?>

http://s44.radikal.ru/i103/0903/b6/9f5ae48fd66d.jpg


if (!empty($input)) {
тогда выводим ответ
}

Gifts 27.03.2009 21:00

Pashkela Он будет всегда не empty, если соединение есть (связано с обработкой socket_select). Скорее надо проверять обратное:
PHP код:

if(empty($input)) die('Соединение разорвано'); 


Pashkela 27.03.2009 21:07

не всегда, как видно, я потестил у себя, ответов иногда разное кол-во, в зависимости от того, какое соединение, банально F5 несколько раз и сразу видно результат

Gifts 27.03.2009 21:29

В общем, должно выглядеть почти так.
PHP код:

<?

$JABBER_SERVER 
"jabber.ru";     
$PORT 5222;      
$i=0;      
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP);       
if(!
$socket) { echo 'soket open - NO'; exit; } else { echo 'socket open - OK<br>'; }        

$connect socket_connect($socket$JABBER_SERVER$PORT);       

if(!
$connect) { echo 'soket connect - NO'; exit; } else { echo 'socket connect - OK<br>'; }         

$t "<stream:stream to='jabber.ru' xmlns='jabber:client' ";     
$t .= "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'>";        

echo 
'<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>';       

socket_write($socket$t);             


while (
1)  {              
    
$read=array($socket);          
    
$count=socket_select($read,$write=null,$exception=null,1);          
    
// Если ничего не пришло пропускаем         
    // Или если нужно что то послать по собственному желанию - отправляем          
    
if ($i++ > 10) break; // Соединение оборвется через 5 секунд или 5 принятых пакетов    
    
if ($count<1) continue;                 
    foreach (
$read as $one) {                  
        
$input=socket_read($one,4096);                  
        if (empty(
$input)) die('Соединение разорвано');
        echo 
'<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>";
        if (
stripos($input,'stream:feature')!==false
        {
            
$t="<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />";
            
socket_write($one,$t);echo '<b>Клиент - </b>'.htmlspecialchars($t).'<br><br>';
        }
        if (
stripos($input,'challenge')!==false
        {
            echo 
'<br/><br/> А теперь разгадывай челленджы сасла: '.htmlspecialchars(base64_decode(strip_tags($input)));
        }
    }      
}


Krist_ALL 27.03.2009 21:40

спаСИБО ОГРОМНОЕЙ !

Krist_ALL 27.03.2009 21:40

спаСИБО ОГРОМНОЕЙ !но на этом я не закончу-завтра продолжу. Всем спасибо!

Krist_ALL 28.03.2009 20:18

Итак продолжим!

После отпраки серверу пакета, который содержит метод авторизации (дигест мд5), мне приходит ответ в басе64, раскодировываю и получаю значение nonce. Я теперь должен отправить пакет который будет содержать:
username='jid',
realm = 'jabber.ru',
nonce=123123123132',
cnonce='????????',
nc=0000001,
qop=auth,
digest-uri='xmpp/jabber.ru', charset=utf-8,response=!!!!!!!!!

Итак, что жея хотел спросить. nonce Эт понятно, оно у нас уже есть,а вот что писать в поле cnonce? В документации сказано что этоуникальный код ответной клинтской сессии, сгенерированный клиентом.... Как понимать не знаю.
Про response молчу.

И еще, мне кажется вайл тут неочень.. может фор? Потомут что я хочу сделать отдельно авторизацию и отделюно прослушку ответов...

А вообше мне кажется моя идея очень замечательная т.к. бот будет на пхп а не на питоне, то даст возможность запускать его на хостингах а не на серваках. Потому что иметь сервак и знать как с ним управится не каждый может, а вот оплатить хостинг и залить на него бота - почти каждый)

Gifts 28.03.2009 20:34

Krist_ALL Читайте RFC2831. Например тут: http://www.faqs.org/rfcs/rfc2831.html

И собственно rfc3920bis. Все вопросы отпадут сами собой

cnonce - это любая строка, например можно использовать MD5 от текущего времени. А response - функция от всех этих параметров

З.Ы, если вы думаете, что PHP класс для джаббера никто до этого не придумал - вы ошибаетесь (например XMPPHP, jabberPHP)
З.Ы.Ы, Зачем выдумывать лисапед (это к вашей фразе о циклах)? Вы как раз вернетесь к тому же, с чего начали - почему вам не приходят все ответы

Krist_ALL 28.03.2009 20:57

Я знаю про php класс. Я об этом писал в начале темы.

Я пишу простой код - простой всмысле понятный. и признаться не знаю классы и хочу написть не исползуя классы.

Пасибо за ссылку на ртфм.

Krist_ALL 29.03.2009 21:03

Хотелось бы попдробнее чтоб кто-нибудь прокоментировал данный кусок кода

PHP код:

while (1)  
{                     

$read=array($socket);                 
$count=socket_select($read,$write=null,$exception=null,1);                 

// Если ничего не пришло пропускаем                
// Или если нужно что то послать по собственному желанию - отправляем                 

if ($i++ > 10) break;  // Соединение оборвется через 5 секунд или 5 принятых пакетов           
if ($count<1) continue; 

Почему вместо if ($i++ > 10) break; не сделать фор и=0; и<10?

Почему через 5 пакетов а не 10? Ведь if ($i++ > 10)

Gifts 29.03.2009 21:45

Krist_ALL Я просто не правил комментарий, да, там 10 пакетов будет. Этот бряк по сути нужен, только для отладки приложения. Потому что еще нет условий, по которому надо выходить из цикла. Когда скрипт дорастет до того, что будет проверять большую часть исключений (ака соединение разорвано, пришел пакет '</stream:stream>' и прочие), тогда от этой строки можно будет избавиться.

Krist_ALL 29.03.2009 22:36

Если не бреак то тада цикл будет бесконечным и зависнет)

Как же хочется фор для авторизации а потом вайл для приема сообщений.

Gifts 29.03.2009 22:57

Krist_ALL Еще раз вопрос - зачем? У тебя получится два АБСОЛЮТНО одинаковых цикла, просто в одном будешь обрабатывать одно, во втором - другое.

Цитата:

Если не бреак то тада цикл будет бесконечным и зависнет)
Еще раз - когда цикл будет обрабатывать все исключения - цикл будут прерывать эти самые обработчики исключений.


Время: 00:54