swoole(3)网络服务模型(单进程阻塞、预派生子进程、单进程阻塞复用模型)
一:单进程阻塞
设计流程:
- 创建一个socket,绑定端口bind,监听端口listen
- 进入while循环,阻塞在accept操作上,等待客户端连接进入,进入睡眠状态,直到有新的客户发起connet到服务器,accept函数返回客户端的socket
- 利用fread读取客户端socket当中的数据,收到数据后服务器程序进程处理,然后使用fwrite向客户端发送响应

代码:
<?php
class Worker{
//监听socket
protected $socket = NULL;
//连接事件回调
public $onConnect = NULL;
//接收消息事件回调
public $onMessage = NULL;
public function __construct($socket_address) {
$this->socket=stream_socket_server($socket_address);
} public function start() {
while (true) {
$clientSocket = stream_socket_accept($this->socket);
if (!empty($clientSocket) && is_callable($this->onConnect)) {
//触发连接事件的回掉
call_user_func($this->onConnect, $clientSocket);
}
//读取内容
$buffer = fread($clientSocket, 65535);
if (!empty($buffer) && is_callable($this->onMessage)) {
call_user_func($this->onMessage, $clientSocket, $buffer);
}
fclose($clientSocket);
}
}
} $worker = new Worker('tcp://0.0.0.0:9810'); $worker->onConnect = function ($args) {
echo "新的连接来了.{$args}.PHP_EOL";
};
$worker->onMessage = function ($conn, $message) {
var_dump($conn, $message);
$content="hello word qwe";
$http_resonse = "HTTP/1.1 200 OK\r\n";
$http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n";
$http_resonse .= "Connection: keep-alive\r\n";
$http_resonse .= "Server: php socket server\r\n";
$http_resonse .= "Content-length: ".strlen($content)."\r\n\r\n";
$http_resonse .= $content;
fwrite($conn, $http_resonse);
};
$worker->start();
cli下运行:
浏览器:
缺点:一次只能处理一个连接,不支持多个连接同时处理
二:预派生子进程模式
设计流程:

- 创建一个socket,绑定服务器端口(bind),监听端口(listen)
- 通过
pcntl_fork函数创建N个子进程 - 一个子进程创建成功后都去阻塞监听新的客户端连接
- 客户端连接时,其中一个子进程被唤醒,处理客户端请求
- 请求完成后,等待主进程回收子进程pcntl_wait
通过调用fork函数来创建子进程,会返回两个pid(主进程id、子进程id)
显示规则:
- 在父进程:fork函数返回子进程id
- 在子进程:fork函数返回0
代码:
<?php
class Worker {
//监听socket
protected $socket = NULL;
//连接事件回调
public $onConnect = NULL;
//接收消息事件回调
public $onMessage = NULL;
public $workerNum = 10;
public function __construct($socket_address) {
$this->socket = stream_socket_server($socket_address);
}
//创建子进程
public function fork() {
for ($i = 0; $i < $this->workerNum; $i++) {
$pid = pcntl_fork();
if ($pid < 0) {
exit('创建失败');
} else if ($pid > 0) {
//父进程空间,返回子进程id
} else {
//子进程空间,返回父进程id 0
$this->accept();
}
}
$status = 0;
$pid = pcntl_wait($status);
echo "子进程" . $pid . PHP_EOL;
}
public function accept(){
while (true) {
$clientSocket = stream_socket_accept($this->socket);
var_dump("正在执行任务的pid为:".posix_getpid());
if (!empty($clientSocket) && is_callable($this->onConnect)) {
call_user_func($this->onConnect, $clientSocket);
}
$buffer = fread($clientSocket, 65535);
if (!empty($buffer) && is_callable($this->onMessage)) {
call_user_func($this->onMessage, $clientSocket, $buffer);
}
fclose($clientSocket);
}
}
public function start() {
$this->fork();
}
}
$worker = new Worker('tcp://0.0.0.0:9801');
$worker->onConnect = function ($args) {
echo "新的连接来了.{$args}.PHP_EOL";
};
$worker->onMessage = function ($conn, $message) {
// var_dump($conn, $message);
$content = "hello word qwe";
$http_resonse = "HTTP/1.1 200 OK\r\n";
$http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n";
$http_resonse .= "Connection: keep-alive\r\n";
$http_resonse .= "Server: php socket server\r\n";
$http_resonse .= "Content-length: " . strlen($content) . "\r\n\r\n";
$http_resonse .= $content;
fwrite($conn, $http_resonse);
};
$worker->start();
cli执行结果:


缺点:严重依赖进程的数量解决并发问题,一个客户端连接就需要占用一个进程
三:单进程阻塞复用模型
设计流程:

- 保存所有的socket,通过select系统调用,监听socket描述符的可读事件
- socket在内核监控,一旦发现可读,会从内核空间传递给用户空间,通过逻辑判断是服务端socket可读,还是客户端socket可读
- 如果是服务端socket可读,说明有新的客户端建立,将socket保留到监听数组中
- 如果是客户端socket可读,说明当前已经可以去读取客户端发送过来的内容了,读取了内容,响应给客户端
代码:
<?php
class Worker {
//监听socket
protected $socket = NULL;
//连接事件回调
public $onConnect = NULL;
//接收消息事件回调
public $onMessage = NULL;
public $workerNum = 4 ;
public $allSocket;
public function __construct($socket_address) {
$this->socket = stream_socket_server($socket_address);
stream_set_blocking($this->socket,0);
$this->allSocket[(int)$this->socket]=$this->socket;
}
public function fork() {
// for ($i = 0; $i < $this->workerNum; $i++) {
// $pid = pcntl_fork();
// if ($pid < 0) {
// exit('创建失败');
// } else if ($pid > 0) {
//
// } else {
$this->accept();
// }
// }
// $status = 0;
// $pid = pcntl_wait($status);
// echo "子进程" . $pid . PHP_EOL;
}
public function accept(){
while (true) {
$write =$except =[];
$read= $this->allSocket;
stream_select($read,$write,$except,60);
foreach($read as $index =>$val){
if ($val == $this->socket){
$clientSocket = stream_socket_accept($this->socket);
var_dump(posix_getpid());
if (!empty($clientSocket) && is_callable($this->onConnect)) {
call_user_func($this->onConnect, $clientSocket);
}
$this->allSocket[(int)$clientSocket]=$clientSocket;
}else{
$buffer = fread($val, 65535);
if (empty($buffer)){
if (feof($val) || is_resource($val)){
fclose($val);
unset($this->allSocket[(int)$val]);
continue;
}
}
if (!empty($buffer) && is_callable($this->onMessage)) {
call_user_func($this->onMessage, $val, $buffer);
}
}
}
}
}
public function start() {
$this->fork();
}
}
$worker = new Worker('tcp://0.0.0.0:9800');
$worker->onConnect = function ($args) {
echo "新的连接来了.{$args}.PHP_EOL";
};
$worker->onMessage = function ($conn, $message) {
// var_dump($conn, $message);
$content = "hello word qwe";
$http_resonse = "HTTP/1.1 200 OK\r\n";
$http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n";
$http_resonse .= "Connection: keep-alive\r\n";
$http_resonse .= "Server: php socket server\r\n";
$http_resonse .= "Content-length: " . strlen($content) . "\r\n\r\n";
$http_resonse .= $content;
fwrite($conn, $http_resonse);
};
$worker->start();
缺点:select模式本身缺点(循环遍历处理事件、内核空间传递数据的消耗)、单线程对于大量任务处理乏力
swoole(3)网络服务模型(单进程阻塞、预派生子进程、单进程阻塞复用模型)的更多相关文章
- IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞的比较,recv参数对性能的影响—O_NONBLOCK(open使用)、IPC_NOWAIT(msgrcv)、MSG_DONTWAIT(re
非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明: 基本概念: 阻塞IO:: socket 的阻塞模式 ...
- Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合
上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...
- 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型
进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...
- 阻塞与非阻塞、同步与异步 I/O模型
I/O模型 Linux 下的五种I/O模型 阻塞I/O(blocking I/O) 非阻塞I/O (nonblocking I/O) I/O复用(select 和poll) (I/O multiple ...
- 同步I/O、异步I/O与阻塞I/O、非阻塞I/O的区别
一.I/O I/O (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作. 通常用户进程中的一个完整I/O分为两阶段:用户进程空间<-->内核空间.内核空间< ...
- python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)
昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...
- (原创)JAVA阻塞队列LinkedBlockingQueue 以及非阻塞队列ConcurrentLinkedQueue 的区别
阻塞队列:线程安全 按 FIFO(先进先出)排序元素.队列的头部 是在队列中时间最长的元素.队列的尾部 是在队列中时间最短的元素.新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素.链接 ...
- socket阻塞与非阻塞,同步与异步I/O模型
作者:huangguisu 原文出处:http://blog.csdn.NET/hguisu/article/details/7453390 socket阻塞与非阻塞,同步与异步 1. 概念理解 在进 ...
- Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】
一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...
随机推荐
- linux下nfs共享目录
1. 关掉防火墙 systemctl disable firewalld.service 2. 关掉selinux vim /etc/selinux/config 修改第七行: ...
- 如何查看iOS系统版本在iPhone设备上的占有率
我们平时开发的时候有时要考虑到系统的兼容版本,但是怎么知道各个版本的系统占有率,其实这个苹果官方是有提供的.进入如下链接到的页面就可以知道各大系统版本的占有率了,不过说实在的iPhone用户的系统更新 ...
- springCloud负载均衡Ribbon和Feign的区别
1.什么是负载均衡: 负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据[均匀]分摊到多个操作单元上执行,负载均衡的关键在于[均匀]. 2.常见的负 ...
- 使用 Wintersmith + Serverless Framework 快速创建个人站点
首先我们来介绍下,Wintersmith 是一个简单而灵活的静态站点生成器.采用 markdown 构建,这个是我们的基础条件. Serverless Framework:在 GitHub 上有三万颗 ...
- Spring Boot中@Async的作用
在Spring中,@Async这个注解用于标记的异步的方法.方法上一旦标记了这个方法,当其它线程调用这个方法时,就会开启一个新的线程去异步处理业务逻辑. 此注解的使用说明: 1.此注解可以用在方法上, ...
- 吴裕雄--天生自然 HADOOP大数据分布式处理:使用XShell远程连接主机与服务器并配置它们之间SSH免密登录
- asp.net---jquery--ajax 实现滚动条滚动到底部分页显示
前台:aspx页面 var bgtime = $(" #date1 ").val(); var overtime = $(" #date2 ").val(); ...
- POJ3264 Balanced Lineup [RMQ模板]
题意:有n头牛,输入他们的身高,求某区间身高的极值的差(max-min), 用RMQ模板,同时构造求极大值和极小值的两个数组. //poj3264 #include <iostream> ...
- Zabbix调用外部脚本发送邮件:python编写脚本
Zabbix调用外部脚本发送邮件的时候,会在命令行传入两个参数,第一个参数就是要发送给哪个邮箱地址,第二个参数就是邮件信息,为了保证可以传入多个参数,所以假设有多个参数传入 #!/usr/bin/en ...
- timber|stain|compensate|
N-UNCOUNT 木材;原木;树木:林木Timber is wood that is used for building houses and making furniture. You can a ...