1、安装workerman
composer require workerman/workerman
2、项目根目录新建一个文件,如 socket.php
将以下内写入此文件
#!/usr/bin/env php
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','push/Socket');
// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';
3、新建socket类
application/push/controller/Socket.php
<?php
namespace app\push\controller;
use app\push\lib\SocketLib;
use Workerman\Lib\Timer;
use Workerman\Worker;
class Socket
{
public function __construct()
{
$config = config('tcp');
$worker = new Worker('tcp://' . $config['host'] . ':' . $config['port']);
$worker->onWorkerStart = function(){
};
$worker->onMessage = function($connection, $data){
//接收消息,记录日志
SocketLib::set_file_log('message is : '. $data, 'message_' . date('Y-m-d'));
$result = SocketLib::handle_reply($connection, $data);
//发送消息,记录日志
SocketLib::set_file_log('send is : '. $result, 'send_' . date('Y-m-d'));
$connection->send($result);
};
//连接时,写日志
$worker->onConnect = function($connection){
SocketLib::set_file_log("new connection from ip " . $connection->getRemoteIp() . "\n");
};
//发生错误,写入日志
$worker->onError = function(\Exception $exception){
SocketLib::set_file_log('error is : '. $exception->getMessage(), 'error_' . date('Y-m-d'));
};
Worker::runAll();
}
}
4、新建SocketLib.php
application/push/lib/SocketLib.php
<?php
namespace app\push\lib;
use think\Exception;
use Workerman\Lib\Timer;
class SocketLib
{
//订阅事件类型
static $_sub_event_list = ['A', 'B', 'C', 'D', 'E', 'F'];
/**
* 处理订阅回复事件
* @param object $con
* @param string $content
*/
public static function handle_reply($con, $content)
{
try {
//解析上报内容,统一解析下
$content = json_decode($content, true);
$event = isset($content['event']) ? $content['event'] : '';
//判断当前订阅事件是否合法
if (in_array($event, self::$_sub_event_list)) {
return self::$event($content); //根据不同的事件类型,执行相对应的方法
} else {
return self::fail($event, '订阅事件不合法');
}
} catch (Exception $e) {
return self::fail($event, $e->getMessage());
}
}
//订阅事件A
public function A($content){
//写业务逻辑
}
//订阅事件B
public function A($content){
//写业务逻辑
}
public static function timer($connection)
{
Timer::add(5, function() use($connection) {
$device_id = $redis->lpop('topic_cabinet_IDQUE_list');
if (! empty($device_id)) {
//执行下发
$result = TcpEvents::handle_reply($connection, '{"ORD":"IDQUE","SN":"'.$device_id.'"}');
$connection->send($result);
}
$device_id = $redis->lpop('topic_cabinet_BUCKID_list');
if (! empty($device_id)) {
//执行下发
$result = TcpEvents::handle_reply($connection, '{"ORD":"BUCKID","SN":"'.$device_id.'"}');
$connection->send($result);
}
});
}
/**
* 成功的返回信息
*/
public static function success($event, $msg = 'success', $extra = [])
{
return json_encode(
array_merge(
[
"event"=> $event,
'msg' => $msg
],
$extra
),
JSON_UNESCAPED_UNICODE
);
}
/**
* 失败的返回信息
*/
public static function fail($event, $msg = 'fail', $extra = [])
{
return json_encode(
array_merge(
[
"event"=> $event,
'msg' => $msg
],
$extra
),
JSON_UNESCAPED_UNICODE
);
}
public static function set_file_log($message, $file = '')
{
try {
$log_file = ROOT_PATH . 'runtime/log/socket/tcp_' . ($file ? $file : date('Y-m-d')) . '.log';
$file_exists = file_exists($log_file) ? true : false;
file_put_contents($log_file, 'time is : ' . date('Y-m-d H:i:s') . ' ' .$message. "\r\n", FILE_APPEND);
if (! $file_exists) @chmod("/somedir/somefile", 0777);
} catch (Exception $e) {
$log_file = ROOT_PATH . 'runtime/log/socket/tcp_catch.log';
$file_exists = file_exists($log_file) ? true : false;
$message = 'catch message is : ' . $e->getMessage();
file_put_contents($log_file, 'time is : ' . date('Y-m-d H:i:s') . ' ' .$message. "\r\n", FILE_APPEND);
if (! $file_exists) @chmod("/somedir/somefile", 0777);
}
if (self::DEBUG) echo $message;
}
}
附注:项目结构
application
--push
--controller/Socket.pph
--lib/SOcketLib.php
socket.php