Php Rachet聊天应用程序-应用程序运行一段时间后,建立连接后立即关闭
我们正在使用Laravel4和Ratchet来创建一个聊天应用程序。一切正常运行约14-20小时。一段时间后,聊天应用程序停止运行。建立从客户端到服务器的连接,但之后服务器立即关闭连接 我们的日志文件中没有报告任何错误,而且我们无法在开发环境中复制该问题的事实也没有帮助 在服务器上重新启动聊天应用程序可将问题修复14-20小时 管理器配置:Php Rachet聊天应用程序-应用程序运行一段时间后,建立连接后立即关闭,php,laravel-4,ratchet,Php,Laravel 4,Ratchet,我们正在使用Laravel4和Ratchet来创建一个聊天应用程序。一切正常运行约14-20小时。一段时间后,聊天应用程序停止运行。建立从客户端到服务器的连接,但之后服务器立即关闭连接 我们的日志文件中没有报告任何错误,而且我们无法在开发环境中复制该问题的事实也没有帮助 在服务器上重新启动聊天应用程序可将问题修复14-20小时 管理器配置: [program:chat] command = bash -c "ulimit -n 10000 && /usr/bin/
[program:chat]
command = bash -c "ulimit -n 10000 && /usr/bin/php /var/www/artisan setup:chat --env=staging"
process_name = chat
numprocs = 1
autostart = true
autorestart = true
user = root
stdout_logfile = /var/www/app/storage/logs/chat_info.log
stdout_logfile_maxbytes = 1MB
stderr_logfile = /var/www/app/storage/logs/chat_error.log
stderr_logfile_maxbytes = 1MB
SetupChatCommand.php(Laravel设置聊天命令):
您确定进程本身在停止工作后不再运行了吗?我不是问你是否确定它不工作,更重要的是它在运行$ps aux | grep artisan
时没有显示。我们遇到了类似的问题,但在我们的案例中,只是在大约相同的时间段后,与数据库的连接被删除。(过程本身仍在正常运行)没关系,我误解了你的部分问题。。我仍然怀疑可能是数据库连接被断开,但我认为如果发生这种情况,会在app/storage/logs/laravel.log
中报告某些情况。您好@watcher,我可以确认聊天应用停止工作后进程仍在运行。当我“ps aux|grep php”时,我得到了两次聊天过程:“bash-c ulimit-n 10000&&/usr/bin/php/var/www/artisan-setup:chat--env=staging”和“/usr/bin/php/var/www/artisan-setup:chat--env=staging”。第一个是用于监视第二个进程的主管进程。@watcher你们是如何修复数据库连接被删除的,你们知道是什么原因导致的吗?我很乐意探索这个场景,看看应用程序是否仍然停止工作。我们不使用supervisor,但我们的“supervisor”每12小时重新启动一次流程:)。没有混乱,没有大惊小怪,但对你来说,这可能不是一个解决办法。
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Application\Chat\Server;
class SetupChatCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'setup:chat';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Setup the chat server';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$server = new Server();
$server->run();
}
}
<?php namespace Application\Chat;
use React\EventLoop\Factory;
use React\Socket\Server as Reactor;
use Ratchet\Server\IoServer;
use Ratchet\Server\FlashPolicy;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class Server {
const CHAT_PORT = 7778;
const FLASH_PORT = 843;
public function __construct()
{
$this->_setup();
}
private function _setup()
{
$loop = Factory::create();
$web_socket = new Reactor($loop);
$web_socket->listen(self::CHAT_PORT, '0.0.0.0');
$this->_server = new IoServer(
new HttpServer(
new WsServer(
new Service()
)
)
, $web_socket
, $loop
);
$flash_policy = new FlashPolicy();
$flash_policy->addAllowedAccess('*', self::CHAT_PORT);
$flash_socket = new Reactor($loop);
$flash_socket->listen(self::FLASH_PORT, '0.0.0.0');
$flash_server = new IoServer($flash_policy, $flash_socket);
}
public function run()
{
$this->_server->run();
}
}
<?php namespace Application\Chat;
use SplObjectStorage;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class Service implements MessageComponentInterface {
public function __construct()
{
$this->_setupClients();
}
/**
* Clients
*/
private $_clients = null;
private function _setupClients()
{
$this->_clients = new SplObjectStorage();
}
public function getClientByConnection($connection)
{
foreach ($this->_clients as $client)
{
if($client->getConnection() === $connection)
{
return $client;
}
}
return null;
}
public function getClientsByRoom($room)
{
$clients = array();
foreach ($this->_clients as $client)
{
if($client->getRoom()->id === $room->id)
{
array_push($clients, $client);
}
}
return $clients;
}
/**
* Input
*/
private function _handleInput($client, $input)
{
if(empty($input) || empty($input['type']) || empty($input['content'])) return;
switch ($input['type'])
{
case 'session.set':
$this->_handleInputSetSession($client, $input['content']);
break;
case 'room.set':
$this->_handleInputSetRoom($client, $input['content']);
break;
case 'message':
$this->_handleInputMessage($client, $input['content']);
break;
}
}
private function _handleInputSetSession($client, $input)
{
$client->setSession($input);
}
private function _handleInputSetRoom($client, $input)
{
$client->setRoom($input);
}
private function _handleInputMessage($client, $input)
{
$message = $client->message($input);
if($client->hasRoom() && $message)
{
$clients = $this->getClientsByRoom($client->getRoom());
foreach ($clients as $other)
{
if($other !== $client)
{
$other->getConnection()->send(json_encode(array(
'type' => 'message.get'
, 'content' => $message->toArray()
)));
}
}
}
}
/**
* Callbacks
*/
public function onOpen(ConnectionInterface $connection)
{
$client = new Client($connection);
$this->_clients->attach($client);
}
public function onMessage(ConnectionInterface $connection, $input)
{
$client = $this->getClientByConnection($connection);
$input = json_decode($input, true);
$this->_handleInput($client, $input);
}
public function onClose(ConnectionInterface $connection)
{
$client = $this->getClientByConnection($connection);
if($client)
{
$this->_clients->detach($client);
}
}
public function onError(ConnectionInterface $connection, \Exception $e)
{
$client = $this->getClientByConnection($connection);
if($client)
{
$client->getConnection()->close();
}
}
}
<?php namespace Application\Chat;
use App;
use Config;
use Application\Models\ChatRoom;
use Application\Models\ChatRoomUser;
use Application\Models\ChatRoomMessage;
use Application\Models\File;
class Client {
/**
* Constructor & Destructor
*/
public function __construct($connection = null)
{
if($connection)
{
$this->setConnection($connection);
}
}
public function __destruct()
{
if($this->hasRoom())
{
$this->takenUserOfflineForRoomId($this->getRoom()->id);
}
}
/**
* Connection
*/
protected $_connection = null;
public function getConnection()
{
return $this->_connection;
}
public function setConnection($connection)
{
$this->_connection = $connection;
}
/**
* Session
*/
public function setSession($input)
{
Config::set('session.driver', 'database');
$session_id = $input;
$session = App::make('session');
$session->setDefaultDriver(Config::get('session.driver'));
$session->driver()->setId($session_id);
$session->driver()->start();
$cartalyst_session = $session->driver()->get(
Config::get('cartalyst/sentry::cookie.key')
);
if(!empty($cartalyst_session))
{
$this->setUserId($cartalyst_session[0]);
}
else
{
throw new \Exception('User not recognized.');
}
}
/**
* User id
*/
private $_user_id = null;
private function setUserId($id)
{
$this->_user_id = $id;
}
public function getUserId()
{
return $this->_user_id;
}
/**
* Room
*/
private $_room = null;
public function getRoom()
{
return $this->_room;
}
public function setRoom($input)
{
if(empty($input) || empty($input['id']))
{
throw new \Exception('Invalid chat room.');
}
$this->_room = ChatRoom::find($input['id']);
$this->takeUserOnlineForRoomId($this->getRoom()->id);
}
public function hasRoom()
{
if($this->_room)
{
return true;
}
return false;
}
/**
* User room status
*/
public function takeUserOnlineForRoomId($room_id)
{
$chat_room_user = ChatRoomUser::where('chat_room_id', '=', $room_id)
->where('user_id', '=', $this->getUserId())
->first();
if($chat_room_user)
{
$chat_room_user->status = ChatRoomUser::STATUS_ONLINE;
$chat_room_user->save();
}
}
public function takenUserOfflineForRoomId($room_id)
{
$chat_room_user = ChatRoomUser::where('chat_room_id', '=', $room_id)
->where('user_id', '=', $this->getUserId())
->first();
if($chat_room_user)
{
$chat_room_user->status = ChatRoomUser::STATUS_OFFLINE;
$chat_room_user->save();
}
}
/**
* Message
*/
public function message($input)
{
$message = new ChatRoomMessage();
$message->user_id = $this->getUserId();
$message->status = ChatRoomMessage::STATUS_NEW;
$message->content = $input['content'];
$chat_room = $this->getRoom();
$chat_room->messages()->save($message);
$this->_attachInputFile($input, $message);
$message->load('user', 'user.profile', 'user.profile.picture');
return $message;
}
private function _attachInputFile($input, $message)
{
if(empty($input['file']) || empty($input['file']['id'])) return;
$file = File::where('user_id', '=', $this->getUserId())
->where('id', '=', $input['file']['id'])
->first();
if(!$file) return;
$message->file()->save($file);
$message->load('file');
}
}