Сокеты в PHP
![]() |
Тему сетевого программирования я еще не затрагивал, поэтому эта статья будет первым шагом в этом направлении. Сокеты, я бы сказал, – основа сетевого взаимодействия на прикладном уровне. С помощью этой технологии две программы, написанные даже на разных языках, могут обмениваться информацией, будучи достаточно удалены друг от друга. Нет, это не то, что изображено на картинке |
Итак, рассмотрим, как реализованы сокеты в PHP, хотя принцип работы с ними одинаковый во всех языках.
Сначала напишем простые клиент и сервер: сервер будет запускаться и ждать соединения, а клиент соединяться к нему и посылать какую-то строку (информацию). А затем я покажу на примере, как отправлять письмо, используя почтовый SMTP-сервер.
Не буду приводить здесь список сокетных функций в PHP. По мере чтения примеров далее Вы сами увидете их.
Пишем простой echo-сервер
Что значит echo-сервер? Это значит, что строка, посланная серверу, возвращается в ответ тому, кто ее послал – клиенту. Т.е. эхо получается по сути.
Сначала нам нужно создать дескриптор сокета:
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
Заметим, что я здесь использовал вызов socket_strerror(socket_last_error()), чтобы определить, в чем была причина ошибки, если вдруг возникла ошибка. Т.е. сначала мы определили номер ошибки с помощью socket_last_error(), а затем этот номер передали в socket_strerror, чтобы превратить его в текстовое описание ошибки.
Теперь нам нужно привязать созданный дескриптор к определенным адресу и порту машины, на которой он будет запущен. Обычно локальный адрес – 127.0.0.1, или localhost. Возьмем порт с номером 10001:
$port = 10001;
echo 'Bind socket ... ';
if (($ret = socket_bind($sock, $address, $port)) < 0) {
throw new Exception('socket_bind() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
Затем нам нужно включить прослушивание этого сокета:
if (($ret = socket_listen($sock, 5)) < 0) {
throw new Exception('socket_listen() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
Цифра 5 здесь означает, что мы разрешим встать в очередь на подключение к этому адресу максимум пяти клиентам.
Когда клиент попытается установить с нами соединение, нам нужно его принять:
if (($msgsock = socket_accept($sock)) < 0) {
throw new Exception('socket_accept() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
После этого дескриптор принятого соединения сохраняется в переменной $msgsock, с которой мы далее будем работать.
Ну а дальше мы просто общаемся с клиентом, отправляя ему данные …
echo "Say to client ($msg) ... ";
socket_write($msgsock, $msg, strlen($msg));
echo "OK\n";
… или принимая их от него:
if (false === ($buf = socket_read($msgsock, 1024))) {
throw new Exception('socket_read() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo $buf."\n";
}
После всего этого «разговора» двух программ, нужно освободить ресурсы, вызвав socket_close:
Приведу полный исходный текст нашего простенького сервера:
server.php
header('Content-Type: text/plain;');
error_reporting(E_ALL ^ E_WARNING);
set_time_limit(0);
ob_implicit_flush();
echo "-= Server =-\n\n";
$address = 'localhost';
$port = 10001;
try {
echo 'Create socket ... ';
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
echo 'Bind socket ... ';
if (($ret = socket_bind($sock, $address, $port)) < 0) {
throw new Exception('socket_bind() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
echo 'Listen socket ... ';
if (($ret = socket_listen($sock, 5)) < 0) {
throw new Exception('socket_listen() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
do {
echo 'Accept socket ... ';
if (($msgsock = socket_accept($sock)) < 0) {
throw new Exception('socket_accept() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
$msg = "Hello, Client!";
echo "Say to client ($msg) ... ";
socket_write($msgsock, $msg, strlen($msg));
echo "OK\n";
do {
echo 'Client said: ';
if (false === ($buf = socket_read($msgsock, 1024))) {
throw new Exception('socket_read() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo $buf."\n";
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf == 'shutdown') {
socket_close($msgsock);
break 2;
}
echo "Say to client ($buf) ... ";
socket_write($msgsock, $buf, strlen($buf));
echo "OK\n";
} while (true);
} while (true);
} catch (Exception $e) {
echo "\nError: ".$e->getMessage();
}
if (isset($sock)) {
echo 'Close socket ... ';
socket_close($sock);
echo "OK\n";
}
?>
Вызовом функции set_time_limit(0), мы говорим интерпретатору, что скрипт может выполняться бесконечно, а не 30 секунд максимум, как по-умолчанию прописано в php.ini.
А вызовом функции ob_implicit_flush мы говорим ему, что выводить строки с помощью echo нужно сразу при их выводе, а не после полной загрузки страницы, как это делается по-умолчанию.
Как видите, в этом простом скрипте мы сохраняем строку, которую нам пришлет клиент, в переменной $buf, затем ее же отправляем обратно клиенту. При этом мы сравниваем эту строку с ‘shutdown’. Если это ‘shutdown’, то корректно завершаем работу сервера.
Теперь запустите этот скрипт в браузере и Вы должны увидеть следующее:
-= Server =-
Create socket … OK
Bind socket … OK
Listen socket … OK
Accept socket …
Т.е. сервер ждет подключения к нему клиента. Ну что ж, не будем заставлять его долго ждать и напишем для него клиента.
Пишем клиента
client.php
header('Content-Type: text/plain;');
error_reporting(E_ALL ^ E_WARNING);
set_time_limit(0);
ob_implicit_flush();
echo "-= Client =-\n\n";
$address = 'localhost';
$port = 10001;
try {
echo 'Create socket ... ';
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0) {
throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
echo 'Connect socket ... ';
$result = socket_connect($socket, $address, $port);
if ($result === false) {
throw new Exception('socket_connect() failed: '.socket_strerror(socket_last_error())."\n");
} else {
echo "OK\n";
}
echo 'Server said: ';
$out = socket_read($socket, 1024);
echo $out."\n";
$msg = "Hello, Server!";
echo "Say to server ($msg) ...";
socket_write($socket, $msg, strlen($msg));
echo "OK\n";
echo 'Server said: ';
$out = socket_read($socket, 1024);
echo $out."\n";
$msg = 'shutdown';
echo "Say to server ($msg) ... ";
socket_write($socket, $msg, strlen($msg));
echo "OK\n";
} catch (Exception $e) {
echo "\nError: ".$e->getMessage();
}
if (isset($socket)) {
echo 'Close socket ... ';
socket_close($socket);
echo "OK\n";
}
?>
Т.е. наш клиент соединяется к серверу по адресу localhost:10001. Далее после вывода того, что ему сказал сервер («Hello, Client!»), он приветствует сервера: «Hello, Server!». Потом сервер отвечает ему тем же (он же echo-сервер
), а клиент отсоединяется от него, посылая команду shutdown.
После запуска этого скрипта, браузер у меня вывел следующие строчки:
-= Client =-
Create socket … OK
Connect socket … OK
Server said: Hello, Client!
Say to server (Hello, Server!) …OK
Server said: Hello, Server!
Say to server (shutdown) … OK
Close socket … OK
При этом вывод сервера выглядел следующим образом:
-= Server =-
Create socket … OK
Bind socket … OK
Listen socket … OK
Accept socket … OK
Say to client (Hello, Client!) … OK
Client said: Hello, Server!
Say to client (Hello, Server!) … OK
Client said: shutdown
Close socket … OK
Итоги
Фух, что-то статья получилась больше, чем я думал. Знаете, давайте я расскажу об отправке email с использованием сокетов в другой статье. Я знаю, что многие интересуются отправкой по SMTP с авторизацией, вот о ней и расскажу. А пока все. Удачных экспериментов с сокетами!

Июль 14th, 2008
Даже не думал, что про сокеты можно вот так вот легко и в то же время подробно расписать) Отличная статья.
P.S. Держи еще одну идею
. С постов в этом блоге получился бы очень неплохой мануал, если собрать все это дело, например в pdf )
Июль 20th, 2008
спасибо, познавательно
Июль 25th, 2008
Я с вами полностью согласен.
Сентябрь 18th, 2008
Автор молодец! 5 баллов, нигде еще не встречал такой подробный и рабочий manual про сокетов в php -
Сентябрь 18th, 2008
2 porfeus: Спасибо! Рад такое слышать, т.е. читать
Сентябрь 20th, 2008
Спасибо, очень полезная статья.
Сентябрь 29th, 2008
Статья действительно очень доступно написана. Жаль только, что у меня не получается на практике поработать с сокетами. Даже не знаю почему. У меня стоит Денвер-3. Может кто-то знает как включить поддержку сокетов?
Октябрь 10th, 2008
Prost: “Может кто-то знает как включить поддержку сокетов” -Заходишь в php.ini, ищешь через поиск строчку ;extension=php_sockets.dll и разкоментируешь ее те убираешь впереди знак-;
Декабрь 24th, 2008
А цп неукого не нагружается??или так и должно быть?
Декабрь 27th, 2008
Спасибо!
Январь 6th, 2009
Супер. Большое спасибо автору
Январь 6th, 2009
Большое пожалуйста читателю
Март 14th, 2009
странно не могу на 3м денвере работать с сокетами. разкоментировал ->скачал php_sockets.dll выдало что не хватает некого файла скачал -> php4ts.dll теперь возмущается что не может найти вход в ф-ю. не подскажете в чем могут быть проблемы?
Апрель 14th, 2009
Необходимо скачать и установить расширения для Денвера PHP 5: дополнительные модули.
Май 24th, 2009
Очень информативно и полезною. Спасибо!
Как раз то, что искал.
Май 28th, 2009
Автору спасибо, коротко, понятно и работает =))
До этой статьи три мануала не осилил =)
Июнь 8th, 2009
Ошибку в socket_create() надо сравнивать с false.
manual
socket_create() returns a socket resource on success, or FALSE on error.
Июль 4th, 2009
Уважаемый автор.
Подскажите пожалуйста как запустить описанный вами сокет-сервер, в ситуации, когда это не единственный php-скрипт в системе?
Т.е. предположим я взаимодействую с сервером написанном на php посредством обычных POST/GET запросов и хочу в каких-то особых случаях запускать сокет-сервер. Например так: получил команду от клиента на создание постоянного соединение, создал сокет, отдал клиенту порт и завершил текущий скрипт, а скрипт с сокет-сервером продолжает работать и закрывает сам себя когда он больше не нужен клиенту.
Я сам предполагаю следующее решение:
- Скрипт обработки команды, определяет порт сокета, который будет использоваться для взаимодействия в дальнешем, возвращает номер порта клиенту (и возможно сохраняет номер порта в бд для других обращений к этому же постоянному соединению), и завершается.
- Получив номер порта, клиент проверяет возможность соединения и если оно не открыто обращается к скрипту сокет-сервера передавая ему номер порта и таким образом запускает его. После чего сокет-сервер работает непоределенное время пока не закроется (по своему усмотрению либо по команде клиента).
Два вопроса в этой связи:
1. Правильно ли я рассуждаю. Представляется ли вам такая инфраструктура использования сокета разумной и корректной.
2. Не правильнее ли будет сразу получив команду запустить сокет-сервер в “автономное плавание” из скрипта обработки команды, с тем, чтобы клиент мог просто соединиться с сокетом, не запуская предварительно соотвествующий скрипт. И если это правильнее, то как это сделать?
С уважением.
Июль 5th, 2009
Дмитрий, я думаю Вам стоит попробовать оба варианта – экспериментируйте и обязательно поймете, что лучше, а что нет. Если я правильно понял вопрос по второму варианту, то Вам нужно запустить скрипт сокетами в автономное плавание примерно следующим образом (тут описан запуск параллельного php-скрипта без передачи ему параметров через POST – передачу сами без труда сделаете):
$fp = fsockopen($server_name, 80);
fwrite($fp,
“POST /script.php HTTP/1.1\r\nHost: “.$server_name.”\r\n”.
“Content-Type: application/x-www-form-urlencoded\r\n”.
“Content-Length: 0\r\n”.
“Connection: close\r\n\r\n”
);
fclose($fp);
И не забывайте про функцию ignore_user_abort.
Июль 6th, 2009
Novice, спасибо большое за советы. Вы позволите, я уточню детали?
Если я правильно Вас понял, Вы предлагаете разместить код сокет-сервера, о котором я писал выше, в файле, который в примере называется “script.php”, верно? И приводите способ его “отправки в автономное плавание”.
Способ неожиданно замысловатый. Учитывая совершенно очевидный недостаток информации по работе с сокетами в PHP, особенно. Получается, что не умея работать с сокетами из php-программы нельзя запустить параллельный (не дочерний) процесс, который не закроется с завершением вызывающего скрипта?
Июль 6th, 2009
Насчет script.php – верно. Насчет запуска параллельного скрипта не с помощью сокетов – я думаю, что сокетами запускать проще всего. Возможно, есть и другие варианты, но, к сожалению, я не обладаю информацией о них. По поводу недостатка информации по работе с сокетами в PHP – если Вы программировали сокеты, например, на C++, то Вам не составит труда понять их и в PHP, т.к. принципы абсолютно те же.
Июль 6th, 2009
Все понял. Еще раз большое спасибо. Сокеты программировал и на плюсах и на Java так что с ними самими никаких трудностей
Некоторые трудности с .. как бы это сказать красиво… с виртуальной машиной PHP
Отсюда и вопросы.
Июль 8th, 2009
Нет, это не то, что изображено на картинке
Это интерфейс обмена информацией сетевыми приложениями.
/* Там сокет под проц же нарисован какойто…. */
Июль 23rd, 2009
Подскажите, как заточить приведенный пример с сокетами под многопользовательскую схему. Я пробую и у меня не получается. Пытаюсь после принятия соединения на accept запихивать $msgsock в архив и работать на прием собщений опрашивая архив в цикле. В том же цикле опрашиваю и слушающий сокет. Но такая схема не работает. Не могу понять. Для каждого подключения новый слушающий нужен чтоли? Объясните пож. кто владеет информацией. Весь инет перерыл. На ПХП очень мало толкового. Спасибо.
Июль 23rd, 2009
Сокеты на PHP должны быть аналогичны сокетам на C++: создается “слушатель” с помощью socket_listen, затем socket_accept сидит в цикле и ждет. Как только к слушающему сокету подключается удаленный клиент, socket_accept создает “экземпляр” соединения и возвращает его, чтобы читать/записывать. Далее, если к этому же слушающему сокету соединяется другой клиент, для него так же socket_accept создает отдельный экземпляр и т.д. То есть получается, что слушающий сокет не нужно трогать – он нужен только для прослушки. А работать надо с ресурсом, который возвращается функцией socket_accept.
Июль 24th, 2009
Вот вот. Я так и пытаюсь делать. Но это не работает. Комп начинает тормозить через минуту работы проги. Память чем то заполняется, хотя у меня стоит проверка переполнения массива с экземплярами сокетов сообщений. Вот код поправьте кто может. Буду рад помощи.
<?php
error_reporting (E_ALL);
/* Разрешить скрипту зависнуть в ожидании соединений. */
set_time_limit (0);
/* Включить неявную очистку вывода, и мы увидим всё получаемое
* по мере поступления. */
ob_implicit_flush ();
$address = ‘192.168.1.4′;
$port = 11000;
if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
echo “socket_create() failed: reason: ” . socket_strerror ($sock) . “\n”;
}
if (($ret = socket_bind ($sock, $address, $port)) < 0) {
echo “socket_bind() failed: reason: ” . socket_strerror ($ret) . “\n”;
}
if (($ret = socket_listen ($sock, 5)) < 0) {
echo “socket_listen() failed: reason: ” . socket_strerror ($ret) . “\n”;
}
$current_conn = 0;
$connections = array();
socket_set_nonblock ($sock);
$listen = true;
while ($listen)
{
if (($new_connection = socket_accept($sock)) $msgsock)
{
if (FALSE === ($buf = socket_read ($msgsock, 2048)))
{
socket_close ($connections[$key]);
unset($connections[$key]);
}
$buf = trim ($buf);
if (empty($buf))
{
continue;
}
if ($buf == ‘q’)
{
socket_write ($msgsock, ‘You exit now!’, strlen ($talkback));
socket_close ($connections[$key]);
unset($connections[$key]);
continue;
}
if ($buf == ’s’ || count($connections) > 10)
{
$listen = false;
break;
}
$talkback = “PHP: You said ‘$buf’.\n”;
socket_write ($msgsock, $talkback, strlen ($talkback));
echo “$buf\n”;
}
}
reset($connections);
foreach ($connections as $key=>$msgsock)
{
$msg = “PHP: Server shuting down!\n”;
socket_write ($msgsock, $msg, strlen($talkback));
socket_close ($connections[$key]);
unset($connections[$key]);
}
socket_close ($sock);
exit();
?>
Июль 24th, 2009
Подскажите, плиз: запускаю вышеприведенный скрипт сервера () и у меня выходит следующее:
-= Server =-
Create socket … OK
Bind socket … OK
Listen socket … OK
Accept socket … OK
Say to client (Hello, Client!) … OK
Client said:
Client said:
Client said:
Client said:
Client said:
Client said:
Client said:
Client said:
………… и т.д.
Т.е. строка “Client said: ” выводится безконечное множество раз. В чем проблема?
Июль 25th, 2009
elvis, это значит, что сервер почему-то принял от клиента пустое сообщение (в коде server.php есть условие).
Июль 25th, 2009
Разобрался наконец. Вот рабочий пример многопользовательской схемы. Работает в одном потоке т.к. в WЦindows pcnctl не поддерживается. Прога криво останавливает сервер. Просто не успел подправить разрыв соединений. Нужно создать флаг завершения и отключать пользователей в цикле while($listen). В остальном работает и наглядно показывает как и что. Вот исходник:
———————————————————–
<?php
error_reporting (E_ALL);
/* Разрешить скрипту зависнуть в ожидании соединений. */
set_time_limit (0);
/* Включить неявную очистку вывода, и мы увидим всё получаемое
* по мере поступления. */
ob_implicit_flush ();
$address = ‘192.168.1.4′;
$port = 11000;
///*
if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
echo “socket_create() failed: reason: ” . socket_strerror ($sock) . “\n”;
}
if (($ret = socket_bind ($sock, $address, $port)) < 0) {
echo “socket_bind() failed: reason: ” . socket_strerror ($ret) . “\n”;
}
if (($ret = socket_listen ($sock, 5)) < 0) {
echo “socket_listen() failed: reason: ” . socket_strerror ($ret) . “\n”;
}
$current_conn = 0;
$connections = array();
socket_set_nonblock ($sock);
$listen = true;
while ($listen)
{
if (($new_connection = @socket_accept($sock)) 0)
{
$num = socket_select($read, $write, $exceptions, $timeout);
echo(”changed sockets number = {$num}\r\n”);
}
// reset($write);
if ($num > 0)
{
echo(”Changed sockets for reading “.count($read).”\r\n”);
foreach ($connections as $key=>$s)
{
//$key = array_search($s, $connections);
$can_write = array_search($s, $write);
$can_read = array_search($s, $read);
if ($can_read !== FALSE) $can_read = true;
if ($can_write !== FALSE) $can_write = true;
if ($can_write && $s === $new_connection)
{
$msg = “\nWelcome to the PHP Test Server. \n” .
“To quit, type ‘quit’. To shut down the server type ’shutdown’.\n”;
socket_write($s, $msg, strlen($msg));
}
echo(”Try read from socket {$key}\r\n”);
if ($can_read && FALSE === ($buf = socket_read ($s, 2048)))
{
socket_close ($connections[$key]);
unset($connections[$key]);
echo(”Unable read from socket {$key} close conection! \r\n”);
continue;
}
if ($can_read)
{
$buf = trim($buf);
echo(”read ‘{$buf}’ from socket {$key}\r\n”);
}
else $buf = ”;
if (empty($buf))
{
continue;
}
if ($buf == ‘q’)
{
if ($can_write)
socket_write ($s, ‘You exit now!’, strlen ($talkback));
socket_close ($connections[$key]);
unset($connections[$key]);
continue;
}
if ($buf == ’s’ || count($connections) > 10)
{
$listen = false;
break;
}
$talkback = “PHP: You said ‘$buf’.\n”;
if ($can_write)
socket_write ($s, $talkback, strlen ($talkback));
echo “$buf\n”;
}
}
}
reset($connections);
foreach ($connections as $key=>$msgsock)
{
$msg = “PHP: Server shuting down!\n”;
socket_write ($msgsock, $msg, strlen($talkback));
socket_close ($connections[$key]);
//unset($connections[$key]);
}
socket_close ($sock);
//*/
exit();
?>
Июль 30th, 2009
Статья хорошая получилась.
Только вот возникают вопросы по многопользовательской системе работы через сокеты.
У меня стоит сервак в сети я запускаю на нем серверную часть и подключаюсь к нему по телнету, все ок.
Но как сделать, чтобы с других компов я мог подключиться к этому сокету?
Август 1st, 2009
Смотри мой пост выше. У меня все работает. С трех компов коннектился. Удачи.
Август 3rd, 2009
Твой пример не работает..
Август 8th, 2009
огромное тебе спс автор!
действительно тикаво читать!
Август 10th, 2009
А что не работает в моем примере? Возможно какие то детали в коде вылетели при модерировании.. Так было с первым постом. Но там простые вещи, которые можно понять и поправить. Вроде отсутствия скобок или т.п.
Август 15th, 2009
ilyichzc, исправь плиз, ошибки в твоем коде, если не сложно. Я попробовал сам исправлять, но мой Апач постоянно ругается – ошибка на ошибке. Кстати, твой код в формате Юникод.
Август 15th, 2009
Если уважаемая администрация позволит, то дам ссылку на скрипт в zip архиве. А то так и будет дырявый код.
Август 21st, 2009
Добрый день!
Очень понравилась статья. Большее спасибо автору!
У меня возник следующие вопросы. Получается, что для того, чтобы все работало, нужно, чтобы был запущен server.php. Тогда:
как сделать так, чтобы он был постоянно запущен? Или какие механизмы есть, чтобы сервер запускался перед тем, как работать с сокетом?
как запустить server.php? То есть я, например, открывал в браузере. А если мне не нужно выводить никакой информации, можно ли сделать как-то, чтобы “серверный” сокет как-то всегда находился в памяти?
Спасибо!
Август 24th, 2009
Чтобы socket.php был постоянно запущен, Вы можете запустить его с помощью тех же сокетов:
$fp = fsockopen($server_name, 80);
fwrite($fp, “POST /server.php HTTP/1.1\r\nHost: “.$server_name.”\r\n”.”Content-Type: application/x-www-form-urlencoded\r\n”.”Content-Length: 0\r\n”.”Connection: close\r\n\r\n”);
fclose($fp);
При этом необходимо, чтобы на сервере директива PHP max_execution_time была установлена в 0, иначе выполнение server.php будет прерываться.
Август 26th, 2009
Не нужно открывать скрипт в браузере. Сделайте batch файл в котором пропишите:
c:/PHP/php-cgi.exe -f d:/work/server/server.php
Август 26th, 2009
Спасибо за помощь!
Решил написать службу, а в ней открывать сокет
Еще раз благодарю за статью!
Сентябрь 7th, 2009
Было бы ваще супер, если бы еще была ссылочка на примерчик в зип(рар)-архиве… Скиньте плыз на мыло(artikz@ya.ru) т.к. временно пропадаю и не смогу ближайших пару месяцев войти в инет.
Сентябрь 7th, 2009
Не подскажите почему выводится ошибка:
Fatal error: Call to undefined function socket_create() in /home/host800681/flexsdk.ru/htdocs/www/flexapps/fex/server.php on line 15
для этой функции нужно что-то дополнительно ставить на сервер?
Ноябрь 5th, 2009
Вобщем начинал я с этого поста и в итоге написал игровой сервер. Под windows работает без нареканий, а под CentOS не могу запустить. Беда такая:
Не хочет работать с mySql сервером. Коннект проходит без ошибок и первый запрос тоже. В первом запросе система проверяет созданы ли нужные таблицы и если нет, то создает их самостоятельно. Дак вот все последующие запросы получают “MySQL server has gone away”, хотя wait_timeout стоит приличный, да и запросы происходят сразу после запуска скрипта. Не подскажет ли кто как победить данную проблему т.к. я в никсах не специалист
Ноябрь 8th, 2009
поведуйте, как в серверном скрипте узнать IP подключившегося клиента?
Ноябрь 16th, 2009
Возник такой вопрос. Как организовать множественное подключение? Т.е. чтобы 2 и больше клиента могли быть, и не могли отключать сервер. Что бы он всегда крутился в системе.
Ноябрь 22nd, 2009
Автор, огромное тебе спасибо:) Довольно подробно и на отлично объясненных примерах все написано! Я – новичек в php и эта статья для меня была очень полезна
Январь 15th, 2010
Здравствуйте, у меня при прочтении статьи возник вопрос.
Когда клиент отрубается от сервера, работа сервера прекращается. ка кже сделать. чтобы он дальше продолжал ловить подключения?
Январь 16th, 2010
В большинстве случаев сокеты используют для обращения к уже
существующим серверам. Если будет желание, попробуйте раскрыть
тему по обращению через сокеты к различным действующим серверам по
различным протоколам. У Вас получается о сложном доступно.
Успехов
Январь 27th, 2010
Vsevolod: Скорее всего у вас в php.ini не подключен модуль
sockets.
Отвечаю на вопросы: “Как сделать, чтобы сервер не отключался после отсоединения клиента?” и “Как обеспечить работу с множественными подключениями?” -
Приведенный мной выше код обеспечивает обработку множества соединений без остановки в реальном времени. Единственное ограничение это цикл обработки одного клиента т.к. остальные все равно стоят в очереди. По этому цикл обработки одного соединения не должен быть очень долгим (например соединение с другим сервером для получения даных по http может занять несколько секунд, что скажется на других пользователях).
Для того, чтобы сервер не останавливался его нужно запускать не из под апача как скрипт, инициируемый браузером, а как самостоятельную резидентную программу -демон, из командной строки. В UNIX обычно php myServer.php. В WINDWS путь к php\php-cgi.exe -f myServer.php. Для нормальной работы программа должна правильно демонизироваться. На эту тему есть достаточно информации в сети. Рекомендую поискать класс PhpDaemon. Он позволяет быстро путем наслодования создать собственный демон.
Январь 27th, 2010
Забыл добавить, что демонизация не обязательна. Программа, запущенная из командной строки и так будет работать пока ее не вырубят. Демонизация же позволяет отвязать процесс от конкретного окна и заставить работать на фоне. В PHP демонизация возможна только в POSIX системах, к которым windows не относится.
Март 29th, 2010
Спасибо большое. Занимаемся написанием игрового сервера Flash + PHP с сокетным соединением (не loadVars() – тоесть вечное нужно соединение). Пост неплохо помог разобраться в самых азах – долго не мог понять как можно вызывать из клиента сервер по IP если у нас server.php имеет вполне определенное имя скрипта. Сразу все встало на места в голове, когда прочел строчку о запуске сервера из браузера.
Если не трудно ilyichzc – пожалуйста, выложите где-нибудь на народе/рапидшаре и т.д. архивчик со скриптом на предмет покопаться. По приведенной ссылке не грузится к сожалению.
Автору поста – радует, когда такие подробные комментарии в тему уточняют сам пост. Это редчайший вариант блогосферы, обычно такое на форумах происходит. Респект!
Апрель 3rd, 2010
Исходника к сожалению не осталось. Есть законченый батлнет для мобильных телефонов. Но то штука комерческая и по этому не могу ее выдать, а выдерать что то оттуда нет времени. Причем начинал делать с этого поста. Многие хулят PHP, что мол медленный очень для таких задач. Я испытывал свой сервер 500 ми ботами, которые одновременно рвали его на части (запрашивали инфу друг про друга, про комнаты, создавали комнаты и т.п.), при этом сервер работал нормально и показал в худшем случае 0.9 миллисекунд задержки на цикл. Так что для первого проекта вполне не плохо, учитывая что разработка занимает не много времени.
Апрель 5th, 2010
Ок, да в принципе и не нужно. Во время освоения мануала и поста показало, что ваш пример почему-то сразу рвет коннект с сервером, telnet при подключении выдает что-то типа “подключение утеряно”. Видимо либо где-то побился кусок кода, либо элементарный баг в счетчике.
А так улыбнуло, что хостер сам не знает, открыты ли у него порты наружу или нет.
Апрель 12th, 2010
2 ilyichzc:
А немогли бы вы выложить “многпоточный скрипт” тот который приводили выше, а то при копирование он не работает, даже с корректировками. И ещё, клиента можно оставить того же что приводит novice или тоже нужен модифицированный?
Апрель 24th, 2010
Видимо, комментарий не прошел антиспам. Хороший, детально документированный (на английском) пример многопоточного (правильнее говоря обрабатывающего более 1 клиента) скрипта находится в комментариях на сайте php.net к функции socket_select() – точную ссылку не привожу чтоб антиспам пропустил. Там же есть мой комментарий с особенностями использования клиента на флеше. Также, есть куски кода на flasher.ru по ссылке forum/showpost.php?p=901346&postcount=7 (сами подставьте)
Апрель 25th, 2010
А вот я кой-чего не могу догнать. Что такое socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); и зачем оно нужно? Такая строчка присутствует в примере кода. Я построил уже на этом примере сокет для игры в кости, все прекрасно работает. Но вот начал детально разбирать код – и так и не смог найти адекватного объяснения зачем это и что это.
Май 14th, 2010
Спасибо за пример, очень помог. А вот как сделать когда 3 и д.т. клиента запущенно сразу, что-бы 1 клиент отправлял другим клиентам сообщения, я через массив замутил, но когда 2 человек просто рубит соеденение, массив не чистится
Июнь 5th, 2010
Статья супер! Так все просто и понятно про написано.
Июнь 8th, 2010
ilyichzc
не могли бы вы выложить еще раз файлы?
Очень нужен много поточный сервер.
Июль 15th, 2010
Такой вопрос. При запуске на локальной машине серверная часть работает нормально. Подключаюсь к сокетам из софтины на дельфе. При установке скрипта на хостинге из вне подключиться не удаётся. Если же запустить простенький скрипт проверки открытых портов на том же хосте показывает что заданный порт открыт. В чём может быть причина что из вне достучаться до порта не получается?