Доброго времени суток, уважаемые форумчане. У меня есть серверное приложение DServer.exe от IL-2 Battle of Stalingrad, приложение принимает команды консоли от RConClient.exe. Я хочу написать некий аналог RConClient.exe на PHP. Из документации следует: Код (Text): Commands, which sre sended to server, and responces, recieved from the serverver are nested into packets. Every packet should have a structure as follows: | length of data | data | | | | The string containing command or responce |00000000| | two bytes | length of string |one byte| So, in fact, the whole packet consists of two bytes, representing the length of data, and the data, which is a C-string (just chars, bytes), terminated with 0-byte. One command/responce is nested in one packet. So as you can see, the maximum packet data lendth is 64K (two bytes for data length). После поисков в интернете, я написал базовый начальный код: PHP: header("Content-Type: text/plain"); $ip = '192.168.1.3' ; $port = '28001'; $timeout = 5; if(!$fp = @fsockopen($ip, $port, $errno, $errstr, $timeout)) { echo $errstr.' ('.$errno.')\r\n'; } else { $out = 'auth 123 123'; // не бинарные данные fwrite($fp, $out); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp); } После длительных поисков примерно понял, что нужно преобразовать данные в бинарный формат. Но вот беда, я не знаю как на php можно преобразовать такую строку в бинарную, используя pack();, чтобы можно было отправить данные и получить ответ, с вышеописанным кодом я только вижу что появляется подключение на стороне серверного приложения, а на стороне клиента, отправляющего запрос средствами php я получаю ошибку по тайм ауту. Прошу вашей помощи в правильном преобразовании строки и отправки данных на сервер, может кто знает?
PHP: function packet_build($data) { return pack("va*", strlen($data) + 1, $data . "\0"); } PHP: $out = packet_build('auth 123 123');
Отлично! данные упакованы, но ответ почему то приходит в виде файла... Хм... Значит нужно обратно как то декодировать ответ от сервера? Тем не менее в файле я получаю: Код (Text): STATUS=6 Что говорит об этом - RCR_ERR_AUTH_INCORRECT=6 Но, если я введу верные данные для авторизации, открывается на стороне сервера сессия, от PHP я уже не получаю ответа, а просто "висю" в режиме ожидания, может как то есть способ отправить 2 команды одновременно, потом закрыть сессию? Не нашёл команды, подобной exit или logout, значит связь заканчивается по таймауту... P.S. Нашёл способ выводить просто в браузере: header("Content-Type: text/html");
Запрос и ответ упакованы одинаково. Сначала два байта указывают размер данных, затем идёт команда или ответ и завершается всё нулевым байтом. PHP: $len = unpack('v', fread($fp, 2))[1]; $str = unpack('Z*', fread($fp, $len))[1]; echo $str;
Если я правильно понял, то скрипт должен выглядеть так: PHP: $timeout = 5; if(!$fp = fsockopen($ip, $port, $errno, $errstr, $timeout)) { echo $errstr.' ('.$errno.')\r\n'; } else { $out = packet_build($cmd); fwrite($fp, $out); while (!feof($fp)) { //echo fgets($fp, 128); $len = unpack('v', fread($fp, 2))[1]; $str = unpack('Z*', fread($fp, $len))[1]; echo $str; } fclose($fp); } Тем не менее, ответ я получаю не сразу, а по истечению времени, и вместе с ним вижу такие ошибки: Warning: unpack(): Type v: not enough input, need 2, have 0 in (...).php on line 28 Warning: fread(): Length parameter must be greater than 0 in (...).php on line 29 Fatal error: Maximum execution time of 300 seconds exceeded in (...).php on line 28 28 и 29 строки соответственно: PHP: $len = unpack('v', fread($fp, 2))[1]; $str = unpack('Z*', fread($fp, $len))[1]; Есть ли какая то возможность получать ответ от сервера сразу, а не по истечении лимита времени?
При таком условии выход из цикла будет только когда сервер закрыл соединение. Это и происходило при неверных логине и пароле. Сейчас соединение продолжает оставаться открытым. PHP: $out = packet_build($cmd); fwrite($fp, $out); $len = unpack('v', fread($fp, 2))[1]; $str = unpack('Z*', fread($fp, $len))[1]; echo $str; fclose($fp);
Работает то как надо, но не могу разобраться каким образом можно отправить 2 команды за раз в 1 сессию чтобы получить необходимый ответ? Попытался циклом, но отправляется только ответ 1-й команды, попробовал сделать два fwrite();, друг за другом, до закрытия соединения fclose(); - аналогично, на 2й команде я уже не авторизован. Консольный клиент RConClient.exe по факту создаёт сессию и в ней работает, но в данном случае я не понимаю как мне попасть внутрь сессии и отправлять туда команды, после уже получить ответ и закрыть соединение.
По идее там сначала формируешь пакет с командой auth и отправляешь. Потом читаешь ответ сервера. Потом формируешь пакет с другой командой и отправляешь. Снова читаешь ответ сервера.
Вы правы, и снова я вам очень благодарен! Теперь код выглядит просто, но правильно: PHP: $out1 = packet_build($auth); $out2 = packet_build($cmd); fwrite($fp, $out1); $len = unpack('v', fread($fp, 2))[1]; $str = unpack('Z*', fread($fp, $len))[1]; echo $str.'<br>'; fwrite($fp, $out2); $len2 = unpack('v', fread($fp, 2))[1]; $str2 = unpack('Z*', fread($fp, $len2))[1]; echo $str2.'<br>'; fclose($fp);