一:单进程阻塞

设计流程:

  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. Linux Centos下MySQL主从Replication同步配置(一主一从)

    MySQL 主从复制概念MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点.MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据 ...

  2. CI_CD(jenkins)公司实战_未完成版

    环境准备 #三台服务器,不同的ip centos   镜像时:CentOS Linux release 7.6.1810 (Core) gitlab-ce 版本是:11.11.3 jenkins   ...

  3. django框架进阶-解决跨域问题

    ####################################### """ 一.为什么会有跨域问题? 是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不 ...

  4. [Linux] Windows 下通过SecureCRT 访问 Linux

    不愿意装双系统的,可以借助虚拟机(Vmware, Virtual PC等) 安装linux 进行使用. 至于如何使用虚拟机安装Linux 这部分,很简单: 下载好需要安装的Linux ISO 镜像文件 ...

  5. [LC] 64. Minimum Path Sum

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  6. 如何单独卸载office2016中的one note

  7. css - 原生变量及使用函数 var()

    零.序言 前两天在逛 blog 的时候看见一些内联样式新奇的写法时很纳闷,虽然说不上多么熟练,但是从来没见过  --color: brown 这样的写法,百度一番之后仍然没啥头绪,今天偶然看到一篇文章 ...

  8. python3的数据类型转换问题

    问题描述:在自我学习的过程中,写了个登陆,在input处,希望能够对数据类型进行判断,但是因为python3的输入的数据会被系统默认为字符串,也就是1,1.2,a.都会被系统默认为字符串,这个心塞啊, ...

  9. php 正则获取html任意标签

    <?php $temp = ' <div class="num">1</div> <div class="num">2 ...

  10. <JZOJ5906>传送门

    emmm dpdpdp然鹅我考场上并想不到 还是凉凉 #include<cstdio> #include<cmath> #include<iostream> #in ...