Jabber бот на php - проблема с сокетами

Discussion in 'PHP' started by Krist_ALL, 27 Mar 2009.

  1. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    Всем привет!
    Решил написать своего джаббер бота на пхп. Не нада кричать что есть готовые бибоиотеки с 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); 

    ?>

     
    #1 Krist_ALL, 27 Mar 2009
    Last edited: 27 Mar 2009
    2 people like this.
  2. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    На многих форумах по пхп мне не помогли. Не знают как сделать...

    Вя надежда на вас!
     
  3. Pashkela

    Pashkela Динозавр

    Joined:
    10 Jan 2008
    Messages:
    2,750
    Likes Received:
    1,044
    Reputations:
    339
    попробуй так:

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

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

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


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

    socket_read($socket, 5000, PHP_NORMAL_READ);


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

    http://ru.php.net/socket_read

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

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    Warning: socket_read() [function.socket-read]: unable to read from socket [104]: Connection reset by peer in ....

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

    KaZ@NoVa Elder - Старейшина

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

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    Плд нормальным! ВОт под каким ты запускаещь скриепт я непойму
     
  7. laedafess

    laedafess Member

    Joined:
    11 Feb 2009
    Messages:
    70
    Likes Received:
    29
    Reputations:
    15
    в пхп надо php_sockets.dll добавить
     
  8. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    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 НЕ требуется указывать длину буфера, если конечно не хочется передавать обрезанные данные
     
    _________________________
    #8 Gifts, 27 Mar 2009
    Last edited: 27 Mar 2009
    1 person likes this.
  9. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    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>";       
    }  
    }
    ?>   
    НА счет типа авторизации - эт канешно сложно, но я выдерну какнить из класса готового.. ПРосто я хочу нааписать своего бота а не готового юзать.
     
  10. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    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>";       
    }  
    }
    ?> 
     
    _________________________
    1 person likes this.
  11. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    Ну вот опять тажа проблема, что и вначале - немогу послать второй пакет, тоестья его ослал но ответа не вижу


    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>";       
       }    
     }                                         
      
    ?>


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

     
  12. Pashkela

    Pashkela Динозавр

    Joined:
    10 Jan 2008
    Messages:
    2,750
    Likes Received:
    1,044
    Reputations:
    339
    /* 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();
     
  13. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    ПРичем тут ob_implicit_flush();...
    В холостую идет чтение опять......
     
  14. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    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'/> ";       
    "/>" Считается закрытием тэга. Уберите слеш
     
    _________________________
    #14 Gifts, 27 Mar 2009
    Last edited: 27 Mar 2009
  15. Pashkela

    Pashkela Динозавр

    Joined:
    10 Jan 2008
    Messages:
    2,750
    Likes Received:
    1,044
    Reputations:
    339
    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>";        
     }  
     }     
     }                                          
      
    ?>
    [​IMG]


    if (!empty($input)) {
    тогда выводим ответ
    }
     
    #15 Pashkela, 27 Mar 2009
    Last edited: 27 Mar 2009
  16. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    Pashkela Он будет всегда не empty, если соединение есть (связано с обработкой socket_select). Скорее надо проверять обратное:
    PHP:
    if(empty($input)) die('Соединение разорвано');
     
    _________________________
  17. Pashkela

    Pashkela Динозавр

    Joined:
    10 Jan 2008
    Messages:
    2,750
    Likes Received:
    1,044
    Reputations:
    339
    не всегда, как видно, я потестил у себя, ответов иногда разное кол-во, в зависимости от того, какое соединение, банально F5 несколько раз и сразу видно результат
     
  18. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    В общем, должно выглядеть почти так.
    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)));
            }
        }      
     
    _________________________
  19. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    спаСИБО ОГРОМНОЕЙ !
     
  20. Krist_ALL

    Krist_ALL Banned

    Joined:
    14 Jan 2009
    Messages:
    436
    Likes Received:
    193
    Reputations:
    24
    спаСИБО ОГРОМНОЕЙ !но на этом я не закончу-завтра продолжу. Всем спасибо!