Вопрос или проблема
OpenSwoole: используйте UDP-сервер для отправки сообщений в канал
Я пытаюсь начать работать с OpenSwoole и использую встроенный UDP сервер. Я хотел бы отправить любые полученные сообщения в канал, чтобы другая корутина могла их обработать. Я много искал в Google и не нашел очевидного способа сделать это.
Вот код, который у меня сейчас есть:
// Создаем канал с местом для 1000 сообщений
$chan = new OpenSwoole\Coroutine\Channel(1000);
co::run(function () use ($chan) {
// Слушатель
go(function() use ($chan) {
// Чтение из канала
while (1) {
$data_read = $chan->pop();
echo ("Данные прочитаны: $data_read\n");
}
});
});
// UDP сервер
// Установите параметры корутины перед запуском сервера
OpenSwoole\Coroutine::set([
'enable_coroutine' => true
]);
// Запустите новый UDP сервер на 12.0.0.1, слушая порт 9502
$server = new OpenSwoole\Server('127.0.0.1', 9502, OpenSwoole\Server::POOL_MODE, OpenSwoole\Constant::SOCK_UDP);
// Настройте обратный вызов события входящих данных, названный 'Packet'
$server->on('Packet', function ($server, $data, $clientInfo) use ($chan)
{
echo ("Данные записаны: $data\n");
$chan->push($data);
});
// Запустите сервер и начните принимать входящие запросы
$server->start();
Но когда я запускаю его, я получаю ошибку:
===================================================================
[ФАТАЛЬНАЯ ОШИБКА]: все корутины (количество: 1) спят - взаимная блокировка!
===================================================================
Как мне завернуть UDP сервер в корутину? Я думал, что он уже работает как корутина, или я что-то очевидное пропустил?
Ответ или решение
Для решения вашей задачи необходимо правильно обернуть UDP-сервер в корутину и убедиться, что поток не блокируется, создавая мертвую блокировку. Ваша текущая попытка создает ситуацию, при которой корутины ждут данные, которые никогда не будут обработаны, что приводит к ошибке мертвого блока.
Для начала, вы должны перенести настройку сервера в корутину и запускать сервер из этой корутины. Таким образом, вы гарантируете, что сервер и его события будут работать в контексте корутины. Вот исправленный код:
// Создание канала с пространством для 1000 сообщений
$chan = new OpenSwoole\Coroutine\Channel(1000);
co::run(function () use ($chan) {
// Короутина для сокета UDP
go(function() use ($chan) {
// слушатель
$server = new OpenSwoole\Server('127.0.0.1', 9502, OpenSwoole\Server::POOL_MODE, OpenSwoole\Constant::SOCK_UDP);
// Установка обработчика для события Packet
$server->on('Packet', function ($server, $data, $clientInfo) use ($chan) {
echo ("Data written: $data\n");
$chan->push($data);
});
// Запуск сервера
$server->start();
});
// Чтение из канала
while (1) {
$data_read = $chan->pop();
echo ("Data read: $data_read\n");
}
});
Объяснение изменений:
-
Упаковка UDP-сервера в корутину: Мы создали новую корутину, в которой находится весь код, связанный с сервером. Это нужно для того, чтобы избежать блокировок между корутинами и позволить им работать независимо друг от друга.
-
Запуск сервера: Сервер запускается внутри корутины, что позволяет ему работать в потоке, поддерживаемом библиотекой OpenSwoole.
- Проверка данных: Чтение данных из канала также выполняется в корутине, что обеспечивает постоянное получение сообщений, поступающих через UDP.
Теперь, когда вы запустите этот код, сервер будет корректно обрабатывать входящие пакеты и отправлять их в канал для дальнейшей обработки, исключая возможность возникновения мертвого блока.