首页 > IT职业 > IT职场 > 二、Swoole学习之玩转网络通信引擎(非常重要)
set函数用于设置swoole_server运行时的各项参数
$serv->set([
'worker_num' => 6 , // worker进程数,cpu 1-4倍
'max_request' => 10000,
]);
/**
* 监听连接进入事件
* $fd 客户端连接的唯一标示
* $reactor_id 线程id
*/
$serv->on('connect', function ($serv, $fd, $reactor_id) {
echo "Client: {$reactor_id} - {$fd}-Connect.n";
});
/**
* 监听数据接收事件
* $reactor_id = $from_id
*/
$serv->on('receive', function ($serv, $fd, $reactor_id, $data) {
echo "client:".$data;
$serv->send($fd, "Server: {$reactor_id} - {$fd}".$data);
});
//监听连接关闭事件
$serv->on('close', function ($serv, $fd) {
echo "Client: Close.n";
});
//启动服务器
$serv->start(); 测试tcp服务器方法:
netstat -anp | grep 9501
通过telnet方式登录远程主机:telnet 127.0.0.1 9501
tcp客户端脚本 查看当前worker进程数:
ps -aft | grep tcp_server.php
connect('127.0.0.1', 9501))
{
exit("connect failed. Error: {$client->errCode}n");
}
//php cli命令行模式 STDOUT常量 向屏幕输出消息
fwrite(STDOUT,"请输入消息:");
$msg = fgets(STDIN);
$client->send($msg);
echo $client->recv();
$client->close(); Tips :为了保证程序执行的完整性,当修改tcp服务器脚本后最好设置平滑重启worker进程
平滑重启worker进程
set(
[
'enable_static_handler' => true,
'document_root' => "/var/www/html/swoole_imooc/demo/data",
]
);
$http_server->on('request',function ($request,$response){
$data = array(
'date:' => date("Ymd H:i:s"),
'get:' => $request->get,
'post:' => $request->post,
'header:' => $request->header,
);
/**
* 异步写文件,调用此函数后会立即返回。当写入完成时会自动回调指定的callback函数
*/
swoole_async_writefile('./access.log', json_encode($data).PHP_EOL,function ($filename){},FILE_APPEND);
$response->cookie('yfyjsz','imooc',time()+1800);
$response->end("sss".json_encode($request->get));
});
$http_server->start(); Tips:阿里云或者腾讯云都需要在安全组设置端口可以访问
2.3 swoole_websocket服务什么websocket
websocket协议是基本web的一种新的网络协议,实现了浏览器和服务器的全双工(==full deple==)允许服务器主动发送消息给客户端
为什么要使用websocket
websocket的特点
- 建立在tcp协议之上
- 性能开销小,通信高效
- 客户端可以和任意服务器通信
- 协议标识符ws wss
- 持久化网络通信标识
1.面向过程实现 ws_server.php
set(
[
'enable_static_handler' => true,
'document_root' => "/var/www/html/swoole_imooc/demo/data",
]
);
$server->on('open', 'onOpen');
//客户端链接时
function onOpen($server,$request){
echo "server: handshake success with fd{$request->fd}n";
}
//ws收到信息时候
$server->on('message', function (swoole_websocket_server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}n";
$server->push($frame->fd, "this is server");
});
//客户端关闭连接时
$server->on('close', function ($ser, $fd) {
//
echo "client {$fd} closedn";
});
$server->start(); 2.面向对象实现ws.php
ws = new swoole_websocket_server(self::HOST,self::PORT);
//php回调函数写法,参考文档https://wiki.swoole.com/wiki/page/458.html
//注意这个$this是$this->ws对象
$this->ws->on('open',array($this,'onOpen'));
$this->ws->on('message',array($this,'onMessage'));
$this->ws->on('close',array($this,'onClose'));
$this->ws->start();
}
/**
* @param $ws
* @param $request
* 监听客户端链接事件
*/
public function onOpen($ws,$request){
print_r('客户端链接:'.$request->fd);
}
/**
* @param $ws
* @param $request
* 监听收到信息事件
*/
public function onMessage($ws,$request){
print_r($ws);
echo "receive from {$request->fd}:{$request->data},opcode:{$request->opcode},fin:{$request->finish}n";
$ws->push($request->fd, "this is server");
}
/**
* @param $ws
* @param $request
* 监听到客户端关闭的事件
*/
public function onClose($ws,$fd){
echo "client close:".$fd;
}
}
new Ws();
ws_测试
yfyjsz_swoole_ws_测试
使用场景
- 广播,发送邮件机制
Tips
- 投递异步任务后会继续往下面执行,不会影响其他的任务
- 当worker进程投递的任务在task_worker中完成时,task进程会通过swoole_server->finish()方法将任务处理的结果发送给worker进程。
- task进程的onTask事件中没有调用finish方法或者return结果,worker进程不会触发onFinish
实现代码:
ws = new swoole_websocket_server(self::HOST,self::PORT);
//php回调函数写法,参考文档https://wiki.swoole.com/wiki/page/458.html
//注意这个$this是$this->ws对象
$this->ws->on('open',array($this,'onOpen'));
$this->ws->on('message',array($this,'onMessage'));
$this->ws->set([
'worker_num'=>2,
'task_worker_num'=>2
]);
$this->ws->on("task", [$this, 'onTask']);
$this->ws->on("finish", [$this, 'onFinish']);
$this->ws->on('close',array($this,'onClose'));
$this->ws->start();
}
/**
* @param $ws
* @param $request
* 监听客户端链接事件
*/
public function onOpen($ws,$request){
print_r('客户端链接:'.$request->fd);
}
/**
* @param $ws
* @param $request
* 监听收到信息事件
*/
public function onMessage($ws,$request){
//TODO 10s
$data = array(
'task'=>1,
'fd'=>$request->fd
);
//广播,发送邮件比较耗时的任务
$ws->task($data);
echo "receive from {$request->fd}:{$request->data},opcode:{$request->opcode},fin:{$request->finish}n";
$ws->push($request->fd, "this is server");
}
public function onTask($serv,$task_id,$src_worker_id, $data){
sleep(10);
print_r($data);
return " i am a task";
}
public function onFinish( $serv, $task_id, $data){
echo "taskId:{$task_id}n";
echo $data;
}
/**
* @param $ws
* @param $request
* 监听到客户端关闭的事件
*/
public function onClose($ws,$fd){
echo "client close:".$fd;
}
}
new Ws(); 三、异步非堵塞IO场景 异步高精度定时器,粒度为毫秒级
//定时执行
swoole_timer_tick(2000, function ($timer_id){
echo "我是异步定时器函数swoole_timer_tick,我的timer_id:{$timer_id}n";
});
//执行一次
swoole_timer_after(5000, function ()use($ws,$request){
echo "我是5s之后在执行的";
$ws->push($request->fd,'我是5s之后在执行的函数');
}); swoole_async_readfile(__DIR__."/1.txt", function($filename, $content) {
echo "filename is {$filename}".PHP_EOL;
echo "content is {$content}".PHP_EOL;
}); $http->on('request', function($request, $response) {
$content = [
'date:' => date("Ymd H:i:s"),
'get:' => $request->get,
'post:' => $request->post,
'header:' => $request->header,
];
swoole_async_writefile(__DIR__."/access.log", json_encode($content).PHP_EOL, function($filename){
// todo
}, FILE_APPEND);
$response->end("response:". json_encode($request->get));
});
[参考文档](https://wiki.swoole.com/wiki/page/185.html) dbConfig = array(
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => '8912878yfy',
'database' => 'test',
'charset' => 'utf8',
);
$this->dbSource = new SwooleMysql;
}
/**
* @param $id
* @param $username
* 执行主函数
*/
public function execute($id,$username){
$this->dbSource->connect($this->dbConfig,function ($db,$result)use($id,$username){
if($result === false) {
var_dump($db->connect_error);
// todo
die;
}
$sql = "insert into user VALUE ('2','yfy')";
//$sql = "show tables";
$db->query($sql,function ($db,$result){
if($result === false){
var_dump($db->error);
}elseif($result === true){ //add update
var_dump($db->affected_rows);
}else{
print_r($result);
}
$db->close();
});
return true;
});
}
}
$obj = new AsyncMysql();
$flag = $obj->execute(1,'yfyjsz');
//先执行后执行sql语句,因为是异步过程
echo 'start';
var_dump($flag);
swoole使用redis的==前置条件==
- redis服务
- hiredis服务
- 编译swoole时需要加--enable-aysnc-redis参数
编译安装hiredis
下载hiredis源码,然后执行
- make -j
- make install
- ldconfig
重新编译swoole
- ./configure --with-php-config=/usr/local/php/bin/php-config --enable-async-redis
- make clean
- make -j & make install
查看php扩展php -m 出现==扩展无法加载==,解决方案如下:
解决方案:
用vi打开当前用户的bash_profile
vi ~/.bash_profile
在最后一行添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
最后再 source ~/.bash_profile
查看安装的扩展的详细信息命令
php --ri swoole
connect('127.0.0.1',6379,function (swoole_redis $redis_client,$result){
var_dump($result.PHP_EOL);
echo "client_connect ok";
$redis_client->set('yfyjsz',time(),function (swoole_redis $redis_client,$result){
if($result == 'OK'){
echo "yfyjsz设置成功";
}else{
echo "yfyjsz设置失败";
}
});
$redis_client->set('yfyjsz1',time(),function (swoole_redis $redis_client,$result){
if($result == 'OK'){
echo "yfyjsz设置成功";
}else{
echo "yfyjsz设置失败";
}
});
$redis_client->get('yfyjsz',function (swoole_redis $redis_client,$result){
var_dump($result);
});
//模糊匹配
$redis_client->keys('*fy*',function (swoole_redis $redis_client,$result){
var_dump($result);
});
echo "startn";
});
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/2844/viewspace-2804764/ ,如需转载,请注明出处,否则将追究法律责任。