epoll模式 主要就是直接对socket进行监听,不需要轮询,如果socket有状态变化就会触发
class Worker{
//监听socket
protected $socket = NULL;
//连接事件回调
public $onConnect = NULL;
public $reusePort=1;
//接收消息事件回调
public $onMessage = NULL;
public $workerNum=2; //子进程个数
public $allSocket; //存放所有socket
public $addr;
public function __construct($socket_address) {
//监听地址+端口
$this->addr=$socket_address;
}
public function start() {
//获取配置文件
$this->fork();
}
public function fork(){
for ($i=0;$iworkerNum;$i++){
$pid=pcntl_fork(); //创建成功会返回子进程id
if($pid<0){
exit("创建失败");
}else if($pid>0){
//父进程空间,返回子进程id
}else{ //返回为0子进程空间
echo "zi";
$this->accept();//子进程负责接收客户端请求
exit;//为什么这里exit退出后子进程不退出?这里应该时阻止继续运行,然后经常在监听,所以没有退出
}
}
exit;//这里如果exit,主进程就会退出来,导致下面结束子进程的代码失效
//放在父进程空间,结束的子进程信息,阻塞状态
$status=0;
for ($i=0;$iworkerNum;$i++) {
$pid = pcntl_wait($status);
}
}
public function accept(){
$opts = array(
"socket" => array(
"backlog" =>10240, //成功建立socket连接的等待个数
),
);
//创建资源流上下文
$context = stream_context_create($opts);
//开启多端口监听,并且实现负载均衡
//stream_context_set_option 设置资源流
// 参数 $stream_or_context, $wrapper, $option, $value
//$stream_or_context 资源流上下文
//$wrapper,包装器(wrapper),包括 http,socket,ssl等
//$option 设置的选项(不确定)
//$value 选项对应的值
//设置端口可以多个监听,开启监听端口复用后允许多个无亲缘关系的进程监听相同的端口,并且由系统内核做负载均衡,
//决定将socket连接交给哪个进程处理,避免了惊群效应,
//可以提升多进程短连接应用的性能。
stream_context_set_option($context,"socket","so_reuseport",1);
stream_context_set_option($context,"socket","so_reuseaddr",1);
$this->socket=stream_socket_server($this->addr,$errno,$errstr,STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,$context);
//第一个需要监听的事件(服务端socket的事件),一旦监听到可读事件之后会触发
//异步监听
swoole_event_add($this->socket,function ($fd){
$clientSocket=stream_socket_accept($fd);
//触发事件的连接的回调
if(!empty($clientSocket) && is_callable($this->onConnect)){
echo "连接事件触发",(int)$clientSocket,PHP_EOL;
call_user_func($this->onConnect,$clientSocket);
}
//监听客户端可读
swoole_event_add($clientSocket,function ($fd){
//从连接当中读取客户端的内容
$buffer=fread($fd,1024);
//如果数据为空,或者为false,不是资源类型
if(empty($buffer)){
if(!is_resource($fd) || feof($fd) ){
//触发关闭事件
fclose($fd);
}
}
//正常读取到数据,触发消息接收事件,响应内容
if(!empty($buffer) && is_callable($this->onMessage)){
call_user_func($this->onMessage,$fd,$buffer);
}
});
});
}
}
$worker = new Worker("tcp://0.0.0.0:9801");
//开启多进程的端口监听
$worker->reusePort = true;
//连接事件
$worker->onConnect = function ($fd) {
echo "连接事件触发",(int)$fd,PHP_EOL;
};
//消息接收
$worker->onMessage = function ($conn, $message) {
var_dump("123");
$content="123123123";
$http_resonse = "HTTP/1.1 200 OK
";
$http_resonse .= "Content-Type: text/html;charset=UTF-8
";
$http_resonse .= "Connection: keep-alive
"; //连接保持
$http_resonse .= "Server: php socket server
";
$http_resonse .= "Content-length: ".strlen($content)."
";
$http_resonse .= $content;
fwrite($conn, $http_resonse);
};
$worker->start(); //启动