Всем привет! Решил написать своего джаббер бота на пхп. Не нада кричать что есть готовые бибоиотеки с xmpp итд, я пишу с нуля. Проблема заключается втом, что функция socket_read читает только один пакет, их бывает приходит 2 или 3, приходится ее писать несколько раз, из-за этого (я так думаю, но не факт что это из-за функции) у меня сбивается порядок огбмена пакеами и соединение рвется что-ли... посылаю данные а ответа не вижу (еслиб я допустил ошибку в формировании данных, пришел бы пакет, говорящий об ошибке в синтаксисе) .. Помогите плз. PHP: <?php $JABBER_SERVER = "jabber.ru"; $PORT = 5222; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_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($socket, 5000); echo '<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>"; $data = socket_read($socket, 5000); echo '<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>"; $data = socket_read($socket, 5000); 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($socket, 5000); echo '<b>Ответ от jabber - </b>'.htmlspecialchars($data)."<br><br>"; //socket_close($socket); ?>
попробуй так: 1. $t = блаблабалбала и в конце всегда ."\n"; 2. Явно указать длину того, чего пишешь: socket_write($socket, $t, strlen($t)); 3. Читать можно попробовать так: socket_read($socket, 5000, PHP_NORMAL_READ); А вообще читай: http://ru.php.net/socket_read там есть примеры работы с сокетами, правильные примеры
Warning: socket_read() [function.socket-read]: unable to read from socket [104]: Connection reset by peer in .... Сделал как сказал Pashkela но вот такая штука вылезла.....
ты под каким Php этот код писал. У меня ошибку пишет, что функции socket_create не существует. И я не пойму, что означают строки вида: <auth xmlns='urn:ietfarams:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5' />
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 НЕ требуется указывать длину буфера, если конечно не хочется передавать обрезанные данные
Gifts, сделал я как ты написал, но чет скрипт зависв браузере - полаеися бесконечный цикл же вайл PHP: <?php $JABBER_SERVER = "jabber.ru"; $PORT = 5222; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_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>"; } } ?> НА счет типа авторизации - эт канешно сложно, но я выдерну какнить из класса готового.. ПРосто я хочу нааписать своего бота а не готового юзать.
Krist_ALL Естественно "завис". Клиент принял пакет и в бесконечном цикле ждет, когда придет следующий, а в браузер ничего не выводится из-за буферизации вывода. Сделай так: PHP: <?php $JABBER_SERVER = "jabber.ru"; $PORT = 5222; $i=0; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_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); echo "htmlspecialchars($input)"; // Тут обработка принятого пакета // например если пришел пакет stream features ответить пакетом начала SASL авторизации // echo '<b>Ответ от jabber - </b>'.htmlspecialchars($input)."<br><br>"; } } ?>
Ну вот опять тажа проблема, что и вначале - немогу послать второй пакет, тоестья его ослал но ответа не вижу PHP: <?php $JABBER_SERVER = "jabber.ru"; $PORT = 5222; $i=0; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_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>"; } } ?> Вот что выводтся в браузере
/* 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 Господи, что Вы делаете. Цикл обработки будет один! не надо его копипастить сто тыщ раз. Я специально комментарий оставил где должна быть обработка. Объясняю, на том месте должно быть что-то вроде: 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'/> "; "/>" Считается закрытием тэга. Уберите слеш
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_INET, SOCK_STREAM, SOL_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>"; } } } ?> if (!empty($input)) { тогда выводим ответ }
Pashkela Он будет всегда не empty, если соединение есть (связано с обработкой socket_select). Скорее надо проверять обратное: PHP: if(empty($input)) die('Соединение разорвано');
не всегда, как видно, я потестил у себя, ответов иногда разное кол-во, в зависимости от того, какое соединение, банально F5 несколько раз и сразу видно результат
В общем, должно выглядеть почти так. PHP: <? $JABBER_SERVER = "jabber.ru"; $PORT = 5222; $i=0; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_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))); } } }