用 PHP 编写 http 服务器
概述
众所周知,我们一般使用 PHP 开发Web程序时需要使用到比如Apache或Nginx等Web服务器来支持,那么有没有办法直接使用PHP开发HTTP服务器,答案当然是可以的,最近看了一遍Workerman框架的源码,于是自己仿照写了一个简易的HTTP服务器,学习为主。本文涉及到知识点包括:
- PHP Socket编程
- 网络 IO 模型
- PHP libevent
- PHP 多进程
- PHP 扩展信号
如何编写 HTTP 服务器
下面是一个简易版HTTP服务器,HTTP 是应用层,其实底层用的是 TCP,在TCP 的基础上包了一层 HTTP的协议。代码如下:
require_once 'Http.php';
$socket = stream_socket_server("0.0.0.0:2345", $errno, $errstr); if (!$socket) {
echo "$errstr ($errno)<br />\n";
} else {
while (true) {
$conn = @stream_socket_accept($socket);
if ($conn)
{
$data = Http::encode('Hi world');
fwrite($conn, $data);
fclose($conn);
} else {
echo "no newSocket\n";
}
}
}
几行代码就可以实现一个简单的 web 服务器,在 shell 下面执行下面命令,在浏览器输入:http://127.0.0.1:2345/ 即可看到 Hi world。
php simple_http_server.php
上面那那种构架,阻塞模式,要等前一个处理完了,才能处理下一个。所以流量稍微大一点,就会处理不过来。那我们可以改进一下,变成多进程模式。
require_once 'Http.php';
$socket = stream_socket_server("0.0.0.0:2345", $errno, $errstr); if (!$socket) {
echo "$errstr ($errno)<br />\n";
} else {
while (true) { if (pcntl_fork() == 0)
{
$conn = @stream_socket_accept($socket); if ($conn)
{
$data = Http::encode('Hi world');
fwrite($conn, $data);
fclose($conn);
} else {
echo "no newSocket\n";
}
}
}
}
这种模式最大的问题是,进程/线程创建和销毁的开销很大。所以上面的模式没办法应用于非常繁忙的服务器程序
高性能的服务器
其实IO复用的历史和多进程一样长,Linux很早就提供了 select 系统调用,可以在一个进程内维持1024个连接。后来又加入了poll系统调用,poll做了一些改进,解决了 1024 限制的问题,可以维持任意数量的连接。但select/poll还有一个问题就是,它需要循环检测连接是否有事件。这样问题就来了,如果服务器有100万个连接,在某一时间只有一个连接向服务器发送了数据,select/poll需要做循环100万次,其中只有1次是命中的,剩下的99万9999次都是无效的,白白浪费了CPU资源。
直到Linux 2.6内核提供了新的epoll系统调用,可以维持无限数量的连接,而且无需轮询,这才真正解决了 C10K 问题。现在各种高并发异步IO的服务器程序都是基于epoll实现的,比如Nginx、Node.js、Erlang、Golang。像 Node.js 这样单进程单线程的程序,都可以维持超过1百万TCP连接,全部归功于epoll技术。
libevent是一个轻量级的基于事件驱动的高性能的开源网络库,并且支持多个平台,依据系统提供的select,poll和epoll方法来进行I/O复用,但是针对于多个系统平台上的不同的I/O复用实现方式,libevent进行了重新的封装,并提供了统一的API接口。libevent在实现上使用了事件驱动这种机制。
我们通过 多进程 + libevent 来构架 web 服务器,结构图如下:
具体的代码可以到 demo, 执行 php demo.php start 即可。
压力测试
硬件是自己 Mac pro,依据 1000 并发重复 100次进行测试:
先测试一个 Nginx + fpm ,siege -c 1000 -r 100 http://yii2.localhost/ 结果如下:
再测试自己写的服务器 siege -c 1000 -r 100 http://127.0.0.0:2345
自己写的服务器成功率几乎是 Nginx + fpm 的 2 倍 。
用 PHP 编写 http 服务器的更多相关文章
- 实战WEB 服务器(JAVA编写WEB服务器)
实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报 分类: ...
- 【北航软件工程】Alpha阶段前端页面编写及服务器部署
前端页面编写 虽然之前对html语法有过一些了解,但是完全没有编写前端页面的经验,和我合作的czy大概也是这么个情况.在Alpha阶段的前端页面编写过程中,我们是摸着石头过河,html是个入门很快专精 ...
- Golang 编写 Tcp 服务器
Golang 作为广泛用于服务端和云计算领域的编程语言,tcp socket 是其中至关重要的功能.无论是 WEB 服务器还是各类中间件都离不开 tcp socket 的支持. Echo 服务器 拆包 ...
- 使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序(系列文章)
在 <用C++实现类似于JAVA HttpServlet 的编程接口 > 文章中讲了如何用 HttpServlet 等相关类编写 CGI 程序,于是有网友提出了 CGI 程序低效性,不错, ...
- 深入学习用 Go 编写 HTTP 服务器
Go是一门通用的编程语言,想要学习 Go 语言的 Web 开发,就必须知道如何用 Go 启动一个 HTTP 服务器用于接收和响应来自客户端的 HTTP 请求.用 Go实现一个http server非常 ...
- php编写tcp服务器和客户端程序
这是我从别的地方看到的. 1.修改php.ini,打开extension=php_sockets.dll 2.客户端程序 SocketClient.php <?php set_time_limi ...
- JAVA编写WEB服务器
一.超文本传输协议 1.1 HTTP请求 1.2 HTTP应答 二.Socket类 三.ServerSocket类 四.Web服务器实例 4.1 HttpServer类 4.2 Requ ...
- io复用select方法编写的服务器
摘要:io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作.select函数作为io多路复用的机制,第一个参数nfds是f ...
- 01-简单编写http服务器
package com.day3; import java.io.IOException; import java.io.InputStream; import java.net.ServerSock ...
随机推荐
- 常用类一一字符串相关类一一StringBuilder,StringBuffer。
package cn.bjsxt.stringbuilder; /** * String 不可变字符序列 * StringBuilder StringBuffer都是是可变字符序列 * 区别在于Str ...
- one by one 项目 part 1
今天安装MySQL,我的系统是win8.1,安装包是mysql-5.7.17-winx64.zip,遇到了不少问题,特在此总结,希望能帮到遇到同样情况的人. 1.前面按照网上教程,先解压,然后在cmd ...
- docker问题
Docker报错 WARNING: IPv4 forwarding is disabled. Networking will not work. 解决办法: # vim /usr/lib/sysctl ...
- Python的logging,记录log的包
最近在做自动化测试时,想给他加上日志,所以用到logging的模块,以下是python增加log的几种方式 一.python代码配置方式(当然还有一种是可以多模块通用的一个python代码设置,这个网 ...
- poj1417(带权并查集+背包DP+路径回溯)
题目链接:http://poj.org/problem;jsessionid=8C1721AF1C7E94E125535692CDB6216C?id=1417 题意:有p1个天使,p2个恶魔,天使只说 ...
- python3 回顾笔记1
http://www.runoob.com/python3/python3-tutorial.html这个网址,可以学习python3的基础语法. 1. 单引号和双引号意义完全相同.用r可以限制转义符 ...
- PTA 习题集5-18 打印选课学生名单(哈希)
假设全校有最多40000名学生和最多2500门课程.现给出每个学生的选课清单,要求输出每门课的选课学生名单. 输入格式: 输入的第一行是两个正整数:N(≤40000),为全校学生总数:K(≤2500) ...
- Django的mode的分组查询和聚合查询和F查询和Q查询
1.聚合查询 # 聚合函数aggregate,求指定字段的最大值,最小值,平均值,和的值,方法如下 from django.db.models import Avg from django.db.mo ...
- Spring_AOP动态代理详解(转)
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- .NET发送请求(get/post/http/https),携带json数据,接收json数据
C#发送https请求有一点要注意: ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateVa ...