(一)如何实现一个单进程阻塞的网络服务器
概述
想要更好的理解,网络编程,写出一个高性能的服务,我们需要花点时间来理解下对于服务器处理客户端的整个流程并且理解一些关键的术语,本来想在本文中补充一些基础理论知识,担心篇幅过长不利于阅读,所以以后补发一些基础知识,接下来进入正题。
理论
主要介绍下实现一个网络服务器的基本步骤,代码会在实践环节复现一次。
第一步
我们需要创建一个socket,绑定服务器端口(bind),监听端口(listen),在PHP中用stream_socket_server一个函数就能完成上面3个步骤。
第二步
进入while循环,阻塞在accept操作上,等待客户端连接进入。此时程序会进入睡眠状态,直到有新的客户端发起connect到服务器,操作系统会唤醒此进程。accept函数返回客户端连接的socket
第三步
利用fread读取客户端socket当中的数据收到数据后服务器程序进行处理然后使用fwrite向客户端发送响应。长连接的服务会持续与客户端交互,而短连接服务一般收到响应就会close。
实践
在这里我们用代码来实现下基本一个流程,在开始写代码之前介绍介几个php函数,是我们代码中可能会用到的,方便大家理解。
函数
stream_socket_server
stream_socket_accept
call_user_func
is_callable
fread
点击函数了解用法
代码
废话少说直接开撸~
<?phpclass Worker{//监听socketprotected $socket = NULL;//连接事件回调public $onConnect = NULL;//接收消息事件回调public $onMessage = NULL;public function __construct($socket_address) {}public function run(){}}$worker = new Worker('tcp://0.0.0.0:9810');
//提前注册了一个连接事件回调
$worker->onConnect = function ($data) {echo '新的连接来了', $data, PHP_EOL;
};
//提前注册了一个接收消息事件回调
$worker->onMessage = function ($conn, $message) {
};
$worker->run();
按照之前的流程我们需要监听端口+地址
public function __construct($socket_address) {//监听地址+端口$this->socket=stream_socket_server($socket_address);}
下一步就需要阻塞在accept操作,等待客户端连接进入。此时程序会进入睡眠状态,直到有新的客户端发起connect到服务器,操作系统会唤醒此进程
public function run(){while (true) { //循环监听$client = stream_socket_accept($this->socket);//在服务端阻塞监听}}
当新的连接进入唤醒进程并且触发连接事件回调
public function run(){while (true) { //循环监听$client = stream_socket_accept($this->socket);//在服务端阻塞监听if(!empty($client) && is_callable($this->onConnect)){//socket连接成功并且是我们的回调//触发事件的连接的回调call_user_func($this->onConnect,$client);}}}
这里的连接回调实际上触发的就是之前准备好类库的这里下面这段代码
$worker->onConnect = function ($data) {echo '连接事件:', $data, PHP_EOL;
};
当连接成功后利用fread获取到客户端的内容,并触发接收消息事件
public function run(){while (true) { //循环监听$client = stream_socket_accept($this->socket);//在服务端阻塞监听if(!empty($client) && is_callable($this->onConnect)){//socket连接成功并且是我们的回调//触发事件的连接的回调call_user_func($this->onConnect,$client);}//从连接中读取客户端内容$buffer=fread($client,65535);//参数2:在缓冲区当中读取的最大字节数//正常读取到数据。触发消息接收事件,进行响应if(!empty($buffer) && is_callable($this->onMessage)){//触发时间的消息接收事件call_user_func($this->onMessage,$this,$client,$buffer);//传递到接收消息事件》当前对象、当前连接、接收到的消息}}}
到此处基本的一个网络服务接收基本完成,还需要对请求做出一个响应,以HTTP请求为例,这里封装了一个http响应的方法(http://127.0.0.1:9810)
class Worker{.........public function send($conn,$content){$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);}}
当触发接收消息事件时对http请求做出响应
$worker->onMessage = function ($server,$conn, $message) {echo '来自客户端消息:',$message,PHP_EOL;$server->send($conn,'来自服务端消息');
};
到这就结束了~,完整代码直通车
缺点
一次只能处理一个连接,不支持多个连接同时处理
(一)如何实现一个单进程阻塞的网络服务器相关推荐
- 【gev】 Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库
gev 轻量.快速的 Golang 网络库 https://github.com/Allenxuxu/gev gev 是一个轻量.快速的基于 Reactor 模式的非阻塞 TCP 网络库,底层并不使用 ...
- golang mysql 非阻塞_Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库...
gev 轻量.快速的 Golang 网络库 gev 是一个轻量.快速的基于 Reactor 模式的非阻塞 TCP 网络库,底层并不使用 golang net 库,而是使用 epoll 和 kqueue ...
- 【硬核】肝了一个月,Cisco网络工程师知识点总结
[硬核]肝了一个月,Cisco网络工程师知识点总结 高能预警,本文是我一个月前就开始写的,所以内容会非常长,当然也非常硬核,有实验,有命令,所以才写到了现在. 我相信90%的读者都不会一口气看完的,因 ...
- 动手做一个自组网的网络 - 操作系统内核
动手做一个自组网的网络 - 操作系统内核 动手做一个自组网的网络 - 项目介绍 动手做一个自组网的网络 - 硬件开发板 动手做一个自组网的网络 - 操作系统内核 动手做一个自组网的网络 - 网络协议栈 ...
- 操作系统:为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?Tomcat服务器工作原理?
为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?这两个问题在我学操作系统以前我都挺困惑的.现在我来尝试着解答一下. 1. 为什么IO操作不占用CPU却会导 ...
- android post请求添加公共参数_XHttp2 一个功能强悍的网络请求库
XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装.还不赶紧点击使用说明文档,体验一下吧! 项目地址 关于我 https://github ...
- 探究!一个数据包在网络中的心路历程
来自:小林coding 前言 想必不少小伙伴面试过程中,会遇到「当键入网址后,到网页显示,其间发生了什么」的面试题. 还别说,这真是挺常问的这题,前几天坐在我旁边的主管电话面试应聘者的时候,也问了这个 ...
- 构建一个业务连续的网络
构建一个业务连续的网络 转载于:https://blog.51cto.com/20194/11365
- linux配置一个ip san存储服务器,网络存储服务ip-san搭建
网络存储服务ip-san搭建 网络存储服务ip-san搭建是一件很冗长的事情,看似间单,实则并不简单,让我们从下面开始学习吧. 一.准备工作 CentOS6.4服务器2台(1台用做IP-SAN存储服务 ...
- 如何做一个国产数据库(六) 网络传输 nodejs做测试客户端
如何做一个国产数据库一 如何做一个国产数据库二 如何做一个国产数据库三 如何做一个国产数据库四 如何做一个国产数据库五 网络实战服务器 我们再四中说过使用tcp进行协议的链接,对我们所定义的协议如果有 ...
最新文章
- 2019年汽车AI计算技术及市场趋势
- centos 7.6安装java_Docker安装zabbix5.0LTS教程和优化
- python同步异步_python中Tornado的同步与异步I/O的介绍(附示例)
- OpenCV文字绘制支持中文显示
- 从单机应用到微服务,用户认证走几步?
- Photoshop基本操作
- java培训学费_北京Java培训班学费很贵吗,包含了哪些收费项目
- ELECTRA模型精讲
- Spring Boot文档阅读笔记-构建Restful风格的WebService客户端
- 机器学习(深度学习)通用工作流程
- MySQL数据库常见存储引擎(一)
- PowerDesigner16工具学习笔记-建立CDM
- CentOS 7完全卸载MySQL
- JavaWeb学习笔记4
- 吴恩达机器学习课后作业6——使用支持向量机(svm)构建一个垃圾邮件分类器
- 小麦亩产一千八(kela)
- kuma相关istio
- ubuntu安装anaconda3报错
- 并发与同步、信号量与管程、生产者消费者问题
- 学习js的第五天【作用域,递归,对象,数组】