今天初步了解了一下关于swoole的相关知识,在这里记录一下。
关于swoole的初步了解记录
安装swoole扩展
- swoole扩展需要在Linux环境下安装,目前还不支持在Windows环境下安装,当前操作系统为centOS系统
- 安装swoole需要:PHP、php-pear(这个是为了稍后可以使用pecl来安装swoole)、php-devel、gcc
- 先执行更新操作 :yum update (已更新过的可以跳过)
- 安装所需环境:yum install php php-pear php-devel httpd(这个是为了安装Apache服务器,已安装过的可去掉) gcc
- 安装swoole:pecl install swoole
- 调整php.ini文件,打开swoole扩展:在 extension = modulename.extension 这一行下面添加 extension=swoole.so
- 使用 php -m 查看swoole扩展是否已安装
搭建TCP服务器
- 1、创建服务器:$serv = new swoole_server($host,$port,$mode,$sock_type);
- $host:服务器地址,如果只监听本地的话可以使用127.0.0.1,如果要监听web的话需要使用服务器的外网ip地,如果服务器有多个IP要监听的话,可以使用0.0.0.0
- $port:端口,如果选择1024以下的端口号需要root权限,1024以上则不用,这里推荐端口9501
- $mode:方式,有默认值,值为SWOOLE_PROCESS,意为多进程的方式,此参数为选填
- $sock_type:启动的服务类型,有默认值,值为SWOOLE_SOCK_TCP,意为启动TCP服务,此参数为选填
2、使用:bool $serv->on(string $event,mixed $callback);- $event:用到的操作事件,分别有 connect(当建立连接时)、receive(当接收到数据时)、close(当关闭连接时)
- $callback:执行某个操作时的回调函数
- 1)、建立连接: $serv->on(‘connect’,function($serv,$fd){ echo ‘建立连接了’;})
- $serv:当前创建的服务器的信息
- $fd:客户端信息 - 2)、接收: $serv->on(‘receive’,function($serv,$fd,$from_id,$data){ echo ‘接收到数据’;})
- $serv:当前创建的服务器的信息
- $fd:客户端信息
- $from_id: 客户端id
- $data: 传递的数据 - 3)、关闭连接: $serv->on(‘close’,function($serv,$fd){ echo ‘关闭连接’;})
- $serv:当前创建的服务器的信息
- $fd:客户端信息
3、启动服务:$serv->start();
搭建UDP服务器
-
1、创建服务器:$serv = new swoole_server($host,$port,$mode,$sock_type);
- $host:服务器地址,如果只监听本地的话可以使用127.0.0.1,如果要监听web的话需要使用服务器的外网ip地,如果服务器有多个IP要监听的话,可以使用0.0.0.0
- $port:端口,如果选择1024以下的端口号需要root权限,1024以上则不用,这里推荐端口9501
- $mode:方式,有默认值,值为SWOOLE_PROCESS,意为多进程的方式,此参数为选填
- $sock_type:启动的服务类型,这里不能使用默认值,需要填SWOOLE_SOCK_UDP,意为启动UDP服务
2、使用:bool $serv->on(string $event,mixed $callback); - $event:用到的操作事件,packet(监听数据接收)
- $callback:执行某个操作时的回调函数
- 1)、监听数据接收: $serv->on(‘packet’,function($serv,$data,$fd){
//发送数据到相应的客户端,反馈信息
$serv->sendto($fd[‘address’],$fa[‘port’],$data); //客户端的IP地址,客户端的端口号,客户端要发送的数据
})- $serv:当前创建的服务器的信息
- $data:接收到的数据
- $fd:客户端的信息
3、启动服务:$serv->start();
web服务器
- 1、创建实例:$serv = new swoole_http_server($host,$port)
- 2、监听获取请求(客户端发起请求时触发):$serv->on(‘request’,function($request,$response){
$response->header(‘Content-type’,‘text/html;charset=utf8’); //设置返回头信息
$response->end(‘我是返回的数据内容’); //设置返回的信息
})- $request:请求信息,有get和post两种方式
- $response:返回信息
3、启动服务:$serv->start();
webSocket服务器 (这个需要创建前台的websocket,即前端使用js创建的websocket)
-
1、创建实例:$ws = new swoole_websocket_server($host,$port)
2、使用:bool $ws->on(string $event,mixed $callback);
- $event:用到的操作事件,分别有 open(建立连接时)、message(接收到数据时)、close(当关闭连接时)
- $callback:执行某个操作时的回调函数
- 1)、建立连接时: $serv->on(‘open’,function($ws,$request){
//发送信息到客户端
$ws->push($request->fd,‘这里是发送的信息内容’)
})
- $ws:当前创建的服务器
- $request:客户端信息
- $request->fd:目标客户端
- 2)、接收信息时: $ws->on(‘message’,function($ws,$request){
//接收到的信息
echo $request->data;
//发送信息到客户端
$ws->push($request->fd,‘这里是发送的信息内容’)
})
- $ws:当前创建的服务器
- $request:客户端信息
- $request->fd:目标客户端
- 3)、关闭连接: $ws->on(‘close’,function($ws,$request){ echo ‘关闭连接’;})
- $ws:当前创建的服务器的信息
- $request:客户端信息
3、启动服务:$serv->start();
4、前端的websocket:(js代码)var wsServer = "ws://服务端地址:端口号"; var webSocket = new WebSocket(wsServer); webSocket.onopen = function(evt) { console.log('连接成功'); }; webSocket.onclose = function(evt) { console.log('关闭连接') }; webSocket.onmessage = function(evt) { /*获取到的以及收发的信息*/ console.log(evt.data) }; /*发生错误时*/ webSocket.onerror = function(evt,e) { }
//evt.data获取到的是open事件里的 “这里是发送的信息内容” 这个内容
定时器(规律收发信息)
- 循环触发定时器
- swoole_timer_tick(2000,function($timer_id){ echo $timer_id;});
- $timer_id: 当前的定时器id,这里返回1
- swoole_timer_tick(2000,function($timer_id){ echo $timer_id;});
- 单次触发定时器
- swoole_timer_after(2000,function(){ echo ‘执行了’;});
异步的TCP服务器
-
创建服务器:$serv = new swoole_server($host,$port);
-
设置异步进程工作数量:$serv->set(array(“task_worker_num” => 4));
-
投递异步任务:$serv->on(‘receive’,function($serv,$fd,$from_id,$data){
//投递之前要先获取异步任务的id
$task_id = $serv->task($data); //将要处理的数据放进去,然后返回一个异步任务的id,id从0开始
});- $serv:服务器信息
- $fd:客户端信息
- $from_id:客户端id
- $data:要处理的数据
-
处理异步任务:$serv->on('task),function($serv,$task_id,$from_id,$data){
//处理任务并返回任务的处理结果
$serv->finish($data.‘任务执行完成’)
}; -
处理结果:$serv->on(‘finish’,function($serv,$task_id,$data){
echo ‘执行完成’;
}); -
启动服务:$serv->start();
异步TCP客户端
-
创建异步TCP客户端:$client = mew swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_ASYNC);
-
注册连接成功的回调函数: $client->on(‘connect’,function($cli){
//如果正常的连接到客户端,我们发送一条信息
$cli->send(‘连接成功了’); //TCP用send(),UDP用sendto()
});- $cli:创建的客户端实例信息
-
注册数据接收的回调函数:$client->on(‘receive’,function($cli,$data){
echo ‘接收到数据了’;
});- $cli:此刻的$cli属于服务端信息
- $data: 接收的数据
-
注册连接失败的回调函数:$client->on(‘error’,function($cli){
echo ‘失败了’;
}); -
注册关闭连接的回调函数:$client->on(‘close’,function($cli){
echo ‘连接关闭了’;
}); -
发起连接:$client->connect($host,$port,$time);
- $host:用户客户端的IP地址
- $port:用户客户端的端口
- $time:超时的时间
进程的创建
-
1、创建进程之前先弄好进程对应的执行函数:
function doProcess(swoole_process $worker){
//打印进程id
echo ‘pid:’.$worker->pid;
//为了更清晰的看到效果,延迟十秒
sleep(10);}
-
2、创建进程:$process = new swoole_process(‘doProcess’);
- doProcess:要执行的函数名
-
3、执行进程:$pid = $process->start(); //会返回对应的进程id
- 如果要同时创建多个进程,将2和3一起多复制几遍即可
-
4、执行完成之后,等待结束(也可不等待直接结束,但是直接结束会产生僵尸进程),关闭主进程:swoole_process::wait();
进程事件
-
创建进程之前先弄好进程对应的执行函数:
function doProcess(swoole_process $process){
$process->write(‘进程id:pid为’.$process->pid); //子进程写入信息(写入到管道)
echo ‘写入信息’.$process->id $process->callback;
} -
添加进程事件,向每一个子进程添加需要执行的动作:
foreach($workers as $process){
//添加
swoole_event_add($process->pipe,function($pipe)use($process){
//获取管道读取的数据
$data = $process->read();
echo ‘接收到数据了:’.$data
});
} -
1、设置一个进程池:$workers = []; //进程池
-
2、设置进程池的数量:$worker_num = 3; //创建进程的数量
-
3、循环创建进程:
for($i=0;$i<$worker_num;$i++){
//创建单独的新进程
$process = new swoole_process(‘doProcess’); //doProcess为进程要执行的函数
//启动进程
$pid = $process->start(); //会返回对应的进程id
//将启动之后的进程放到进程池,循环放入
$workers[$pid] = $process
}
进程队列通信
-
创建进程之前先弄好进程对应的执行函数:
function doProcess(swoole_process $process){
$recv = $process->pop(); 长度默认是8192
echo ‘从主进程获取到数据’.$recv;
//为了更清晰的看到效果,延迟十秒
sleep(10);
//当前子进程退出
$process->exit(0);
} -
1、设置一个进程池:$workers = []; //进程池
-
2、设置进程池的数量:$worker_num = 3; //创建进程的数量
-
3、循环创建子进程:
for($i=0;$i<$worker_num;$i++){
//创建单独的新进程
$process = new swoole_process(‘doProcess’,false,false); //doProcess为进程要执行的函数
$process->useQueue; //开启队列,类似于全局函数
//启动进程
$pid = $process->start(); //会返回对应的进程id
//将启动之后的进程放到进程池,循环放入
$workers[$pid] = $process
} -
4、主进程向子进程添加数据
foreach($workers as $pid=>$process){
$process->push(‘hello 子进程:’.$pid)
} -
5、等待子进程结束,回收资源
for($i=0;$i<$worker_num;$i++){
$ret = swoole_process::wait(); //等待执行完成
$pid = $ret[‘pid’];
//结束后删除掉进程池里的对应的进程
unset($workers[$pid]);
echo ‘子进程退出’;
}
信号触发
-
触发函数:swoole_process::signal(SIGALRM,function(){
ehco ‘1’;
}); -
定时信号:swoole_process::alarm(100*1000);//这里是以微秒执行的,我们要100毫秒执行一次,所以要乘以1000
锁机制
- 创建锁对象:$lock = new swoole_lock(SWOLLE_MUTEX); //SWOLLE_MUTEX为互斥锁
- 开始锁定主进程:$lock->lock();
//使用PHP默认的进程模块
if(pcntl_fork() > 0){
sleep(1);
//解锁
$lock->unlock();
}else{
echo ‘子进程等待锁’;
//上锁
$lock->lock();
echo ‘子进程获取锁’;
//解锁
$lock->unlock();
//子进程退出并打印信息
exit(‘子进程退出’);
}
//主进程释放锁
unset($lock);
sleep(1);
//子进程退出
ehco ‘子进程退出’;
DNS查询
- 执行DNS查询:swoole_async_dns_lookup(‘www.baidu.com’,function($host,$ip){
//$host是要查询的域名,$ip是该域名对应的ip
});
异步读取文件
- swoole_async_readfile(DIR.‘文件路径’,function($filename,$content){
//$filename 是要读取的文件的路径,$content是文件内容
});
异步文件写入
- 要写入的内容:$content = ‘卡技术部大卡司’;
- swoole_async_writefile(‘要写入的文件的路径’,‘要写入的内容’,function($filename){},要写入的位置,一般写0);
异步事件
- 模拟异步读取一个网址
$fp = stream_socket_client(“ftp://www.qq.com:80”,$errno,$errstr,30);
//$errno错误码,$errstr错误信息,30时间,单位秒
//写入,模拟请求
fwrite($fp,“GET / HTTP/1.1\r\nHost:www.qq.com\r\n\r\n”); - 添加异步事件:swoole_event_add($fp,function($fp){
//读取一下fp
$resp = fread($fp,8192); //8192为长度
var_dump($resp);
//删除句柄
swoole_event_del($fp);
//关闭
fclose($fp);
})
//为了验证是异步的,我们输出一个字符串,异步的情况下字符串先输出
echo ‘我先出来了’;
异步mysql操作
-
实例化资源:$db = new swoole_mysql();
-
配置连接数据库的参数:
$config = [
‘host’ => ‘数据库地址’,
‘user’ => ‘用户名’,
‘password’=> ‘密码’,
‘datebase’=> ‘数据库名’,
‘charset’ => ‘utf8’
]; -
连接数据:$db->connect($config,function($db,$res){
if($res === false){
//连接失败
var_dump($db->connect_errno,$db->connect)error);
echo ‘连接失败’;
}
//连接成功
$sql = ‘要执行的sql语句’;
$db->query($sql,function(swoole_mysql $db,$res){
if($res === false){
//操作失败
var_dump($db->error);
echo ‘操作失败’;
} elseif($res === true){
var_dump($db->affected,$db->insert_id);
}
//关闭数据库
$db->close();
};
});
如果有错误的地方欢迎指出。