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 ...
随机推荐
- vue中axios的post请求使用form表单格式发送数据
vue使用插件qs实现 (qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库.) 在jquery中的ajax的方法已将此封装,所以不需要再次序列化 1. 安装 在项目中使用命令行工具输 ...
- s01字符串---蓝桥杯
问题描述 s01串初始为"0" 按以下方式变换 0变1,1变01 输入格式 1个整数(0~19) 输出格式 n次变换后s01串 样例输入 3 样例输出 101 数据规模和约定 0~ ...
- php通过身份证判断性别
/** 已测试,百度很多写法不行的 * 1就是男性 2就是女性* 通过身份证获取性别类型* @param type $card* @return int*/function getCardSex($i ...
- android全功能音乐播放器、基于MVP-Clean + Weex + RxJava2 + Retrofit + Dagger2 + MTRVA的综合应用、图片滤镜处理等源码
Android仿微信朋友圈查看图片下拽返回. Android图片滤镜处理,相机滤镜处理效果源码 Android自定义View源码:一个水平的进度条 基于MVP-Clean + Weex + RxJav ...
- ROS中的日志(log)消息
学会使用日志(log)系统,做ROS大型项目的主治医生 通过显示进程的运行状态是好的习惯,但需要确定这样做不会影响到软件的运行效率和输出的清晰度.ROS 日志 (log) 系统的功能就是让进程生成一些 ...
- 吴裕雄--天生自然python学习笔记:python设置文档的格式
Win32com 组件可为特定范围的内 容设置格式, 较常用的格式有标题格式.对齐 方式格式及字体格式 . 许多格式使用 常量表示 , 所 以 需先导入 constants常量模块 : 设置标题格式的 ...
- AngularJS中格式化日期为指定格式字符串
var date = $filter('date')(new Date(),'MM/dd/yyyy');
- nodejs快速测试
对于一些js功能,可以通过nodejs快速搭建测试环境 1.这里我们先通过express脚手架快速搭建一个项目,或者init一个空项目 2.mkdir script 3.这里假设我们的场景是MQTT接 ...
- leetcode第24题:两两交换链表中的节点
通过分析,这属于数据结构类型题目,但涉及到多次交换,也需要算法知识. 首先,我想的是,将链表中节点相互交换. class Solution: def swapPairs(self, head: Lis ...
- Pytorch collate_fn用法
By default, Dataloader use collate_fn method to pack a series of images and target as tensors (first ...