(一)如何实现一个单进程阻塞的网络服务器

news/2025/6/2 12:51:32

图片描述

概述

想要更好的理解,网络编程,写出一个高性能的服务,我们需要花点时间来理解下对于服务器处理客户端的整个流程并且理解一些关键的术语,本来想在本文中补充一些基础理论知识,担心篇幅过长不利于阅读,所以以后补发一些基础知识,接下来进入正题。

理论

主要介绍下实现一个网络服务器的基本步骤,代码会在实践环节复现一次。

clipboard.png

第一步

我们需要创建一个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,'来自服务端消息');
};

到这就结束了~,完整代码直通车

缺点

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

文章来源:https://blog.csdn.net/weixin_34224941/article/details/88629120
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:https://dhexx.cn/news/show-3392796.html

相关文章

树莓派 安装qt

树莓派 安装qt 首先确保树莓派能上网&#xff0c;可以ping www.baidu.com 看看 1. 先将树莓派的内核更新下&#xff0c;当然这一步也可以跳过 sudo apt-get update #更新源列表&#xff0c;换源后必须执行 sudo apt-get dist-upgrade #这一步是更新软件 sudo rpi…

如何在线创建数据流图(DFD)?

想要创建数据流图&#xff08;DFD&#xff09;&#xff1f;我们将为您提供有关DFD的介绍&#xff0c;并告诉您如何使用在线DFD软件创建DFD。 什么是数据流图&#xff1f; 数据流图&#xff08;DFD&#xff09;是在软件设计中经常使用的图。它直观地表示给定系统中整个过程的数据…

Vue学习(三)生命周期函数

每个Vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期。首先官方文档上的图片&#xff1a; 可以看到在vue一整个的生命周期中会有很多钩子函数提供给我们在vue生命周期不同的时刻进行操作, 那么先列出所有的钩子函数&#xff0c;然后我们再一一详解: …

C++ 11 右值引用以及std::move

转载请注明出处&#xff1a;http://blog.csdn.net/luotuo44/article/details/46779063 新类型&#xff1a; int和int&是什么&#xff1f;都是类型。int是整数类型&#xff0c;int&则是整数引用类型。相同int&&也是一个类型。两个引號&&是C 11提出的一个…

线程、进程、携程理解

并发与并行 并发 拥有处理多个任务的能力。对于单核CPU来说&#xff0c;只能处理并发 并行 拥有同时处理多个任务的能力&#xff0c;对于多核CPU&#xff0c;即可以并发和并行 同步与异步 同步和异步强调的是消息通信机制 同步 如果一个人这样处理&#xff1a;先烧水&#xff0…

C++11 multithreading

C11 并发指南七(C11 内存模型一&#xff1a;介绍) Haippy 2013-11-14 16:38 阅读: 32835 评论: 4 推荐: 5 C11 并发指南三(Lock 详解) Haippy 2013-10-02 11:38 阅读: 64782 评论: 6 推荐: 5 C11 并发指南六(atomic 类型详解四 C 风格原子操作介绍) Haippy 2013-09-07 11…

Python 编程快速上手 让繁琐工作自动化-第十一章实践项目 11.11.1命令行邮件程序...

11.11.1 命令行邮件程序 编写一个程序&#xff0c;通过命令行接受电子邮件地址和文本字符串。然后利用selenium登录到你的邮件账号&#xff0c;将该字符串作为邮件&#xff0c;发送到提供的地址&#xff08;你也许希望为这个程序建立一个独立的邮件账号&#xff09;。这是为程序…

C++11 atomic

C11 并发指南七(C11 内存模型一&#xff1a;介绍) Haippy 2013-11-14 16:38 阅读: 32835 评论: 4 推荐: 5 C11 并发指南六(atomic 类型详解四 C 风格原子操作介绍) Haippy 2013-09-07 11:18 阅读: 20676 评论: 1 推荐: 0 C11 并发指南六(atomic 类型详解三 std::atomic (…

论文简介-1

论文 一、本体论在自动问答系统中的应用_骆正华 基于本体来组织问句的方法&#xff0c;并探讨在基础上分析问句的方法&#xff0c;并利用本体向量来联系问句实例和领域知识&#xff0c;达到问题和答案的连接。用户提交的问句 进行分词、 词性标注、 语块划分等浅层句法分析在语…

孙行者下联,有祖冲之与胡适之两种答案,好在哪里

孙行者-祖冲之&#xff1a;孙即子孙&#xff0c;祖即爷爷&#xff0c;孙对祖天经地义&#xff1b;行和冲是动词&#xff0c;所以可以成对&#xff0c;者和之同为虚词&#xff0c;也可成对&#xff0c;孙行者-胡适之&#xff1a;孙者&#xff0c;孙加反犬旁即为狲&#xff0c;胡…