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

栏目: 服务器 · 发布时间: 5年前

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

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

概述

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

理论

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

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

第一步

我们需要创建一个socket,绑定服务器端口(bind),监听端口(listen),在 PHP 中用stream_socket_server一个函数就能完成上面3个步骤。

第二步

进入while循环,阻塞在accept操作上,等待客户端连接进入。此时程序会进入睡眠状态,直到有新的客户端发起connect到服务器,操作系统会唤醒此进程。accept函数返回客户端连接的socket

第三步

利用fread读取客户端socket当中的数据收到数据后服务器程序进行处理然后使用fwrite向客户端发送响应。长连接的服务会持续与客户端交互,而短连接服务一般收到响应就会close。

实践

在这里我们用代码来实现下基本一个流程,在开始写代码之前介绍介几个php函数,是我们代码中可能会用到的,方便大家理解。

函数

点击函数了解用法

代码

废话少说直接开撸~

<?php
 class Worker{
     //监听socket
     protected $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,'来自服务端消息');
};

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

缺点

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


以上所述就是小编给大家介绍的《(一)如何实现一个单进程阻塞的网络服务器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品经理面试宝典

产品经理面试宝典

[美] Gayle Laakmann McDowell、[美]Jackie Bavaro / 吴海星、陈少芸 / 人民邮电出版社 / 2015-3 / 59.00元

本书针对IT 行业产品经理,以面试为主线,首先介绍产品经理职责以及谷歌、微软等知名企业中产品经理的作用和要求;然后采访了几位知名企业的产品经理,介绍成为产品经理的基本素质;之后从简历准备、各公司面试要点到具体面试问题进行详细分析,这部分是本书的重点内容。读者对象包括IT 行业产品经理以及对如何做好产品有兴趣的人士。一起来看看 《产品经理面试宝典》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换