一:单进程阻塞

设计流程:

  1. 创建一个socket,绑定端口bind,监听端口listen
  2. 进入while循环,阻塞在accept操作上,等待客户端连接进入,进入睡眠状态,直到有新的客户发起connet到服务器,accept函数返回客户端的socket
  3. 利用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下运行:

浏览器:

 缺点:一次只能处理一个连接,不支持多个连接同时处理

二:预派生子进程模式

设计流程:

  1. 创建一个socket,绑定服务器端口(bind),监听端口(listen)
  2. 通过pcntl_fork函数创建N个子进程
  3. 一个子进程创建成功后都去阻塞监听新的客户端连接
  4. 客户端连接时,其中一个子进程被唤醒,处理客户端请求
  5. 请求完成后,等待主进程回收子进程pcntl_wait

通过调用fork函数来创建子进程,会返回两个pid(主进程id、子进程id)

显示规则:

  1. 在父进程:fork函数返回子进程id
  2. 在子进程: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执行结果:

 缺点:严重依赖进程的数量解决并发问题,一个客户端连接就需要占用一个进程

三:单进程阻塞复用模型

设计流程:

  1. 保存所有的socket,通过select系统调用,监听socket描述符的可读事件
  2. socket在内核监控,一旦发现可读,会从内核空间传递给用户空间,通过逻辑判断是服务端socket可读,还是客户端socket可读
  3. 如果是服务端socket可读,说明有新的客户端建立,将socket保留到监听数组中
  4. 如果是客户端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)网络服务模型(单进程阻塞、预派生子进程、单进程阻塞复用模型)的更多相关文章

  1. IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞的比较,recv参数对性能的影响—O_NONBLOCK(open使用)、IPC_NOWAIT(msgrcv)、MSG_DONTWAIT(re

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:       基本概念: 阻塞IO:: socket 的阻塞模式 ...

  2. Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合

    上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型.   阻塞IO   过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...

  3. 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型

    进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...

  4. 阻塞与非阻塞、同步与异步 I/O模型

    I/O模型 Linux 下的五种I/O模型 阻塞I/O(blocking I/O) 非阻塞I/O (nonblocking I/O) I/O复用(select 和poll) (I/O multiple ...

  5. 同步I/O、异步I/O与阻塞I/O、非阻塞I/O的区别

    一.I/O I/O (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作. 通常用户进程中的一个完整I/O分为两阶段:用户进程空间<-->内核空间.内核空间< ...

  6. python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  7. (原创)JAVA阻塞队列LinkedBlockingQueue 以及非阻塞队列ConcurrentLinkedQueue 的区别

    阻塞队列:线程安全 按 FIFO(先进先出)排序元素.队列的头部 是在队列中时间最长的元素.队列的尾部 是在队列中时间最短的元素.新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素.链接 ...

  8. socket阻塞与非阻塞,同步与异步I/O模型

    作者:huangguisu 原文出处:http://blog.csdn.NET/hguisu/article/details/7453390 socket阻塞与非阻塞,同步与异步 1. 概念理解 在进 ...

  9. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

随机推荐

  1. 2019-2020-1 20199324《Linux内核原理与分析》第六周作业

    第五章 系统调用的三层机制(下) 1.给MenuOS增加命令 进入Linuxkernel目录下,强制删除当前menu目录,再重新克隆一个新版本的menu 进入menu,运行make roofts脚本就 ...

  2. [LC] 348. Design Tic-Tac-Toe

    Design a Tic-tac-toe game that is played between two players on a nx n grid. You may assume the foll ...

  3. appium自动化的工作原理(1)

    用appium开发移动端自动化测试脚本这么长时间,还没有认证的了解下它的原理是什么,到底是如何实现的呢? 1.先看一个Appium加载的过程图解(来自:了解appium自动化的工作原理--https: ...

  4. TCP、UDP、HTTP与HTTPS

    TCP.UDP.HTTP与HTTPS都是通信协议,在这里首先先介绍一下什么是通信协议. 什么是通信协议? 通信协议(communications protocol)是指双方实体完成通信或服务所必须遵循 ...

  5. 实战_3:新建产品配置(product)并导出项目

    产品配置Product 产品配置用于定义和管理RCP应用的多个方面特征.并支持将RCP项目导出为部署包(类似eclipse压缩包),可以直接部署到其他环境上使用. 产品配置必须新建一个 扩展名为 .p ...

  6. 2010提高组-C]关押罪犯(扩展域并查集

    题:https://www.cometoj.com/problem/0073 #include<bits/stdc++.h> using namespace std; ; struct n ...

  7. 利用git上传文件到github

    git add 文件名称/. "."代表全部 git commit -m -a git push -u origin master 推送到远程仓库 ---------------- ...

  8. fscanf使用心得

    好久没碰C语言了.从现在开始,要开始刷题了. (1)int fscanf( FILE* stream, const char* format, ... ); https://www.programiz ...

  9. ZooKeeper基本讲解及使用

    本文摘录于:http://blog.51cto.com/tchuairen/1859494:https://blog.csdn.net/peace1213/article/details/525714 ...

  10. deeplearning.ai 卷积神经网络 Week 1 卷积神经网络

    1. 传统的边缘检测(比如Sobel)手工设计了3*3的filter(或者叫kernel)的9个权重,在深度学习中,这9个权重都是学习出来的参数,会比手工设计的filter更好,不但可以提取90度.0 ...