短文1:使用 php-socket 简述 http 服务器原理
此节使用 PHP 原生 Socket 演示完成 http 请求的原理
套接字怎么理解
一个典型的网络连接由 2 个套接字构成,一个运行在客户端,另一个运行在服务器端。
“套接字”取名叫做 socket,翻译:“插座”。在网络编程中叫做用于网络数据传输的“软件设备”。
那么通俗理解一点,“套接字” 就是一个文件资源 file
。
以一家拉面馆做比喻
流程概要:假设场景是食城,一家拉面店。通过 create
创建一个服务端套接字,初始化套接字有三个参数,是ipv4还是ipv6、面向连接还是面向消息、tcp 还是 udp ,也就是描述这个套接字是干嘛用,描述我是一家拉面馆。接下来通过 bind
端口号,也就是联系地址,食城第123号能找到我。通过 listen
开始监听,准备好了开始营业(这时店里没人接待,顾客排队等候)。调用 accept
函数等待客户端连接(此处阻塞,直到有客户端连接产生一个客户端文件描述符 fd ),也就是等待客人,直到来了一个顾客,此时店员拿起一张纸片问顾客问吃点啥,随后将纸片转给后厨。后厨 read
纸片上的菜品,然后准备食物 响应
,然后 write
给顾客。顾客走了,卡片也就没用了扔掉了(fd回收),socket_close($client)
结束该顾客的服务。晚上10点,拉面店关门,socket_close($server)
。
PHP 代码
创建一个套接字,$server
表示的是服务端的套接字。描述我是拉面馆。
$server = socket_create(
AF_INET,
SOCK_STREAM,
SOL_TCP);
绑定端口号,0.0.0.0
服务所有人,当然也可以是专供
socket_bind($socket, '0.0.0.0', 80);
开始监听,5
排队中等待接待的顾客人数,地方小门口只能站5个人(资源层面)。
socket_listen($socket, 5);
与一个客户端建立连接,接待了张三
$client = socket_accept($server);
读取客户端信号,张三:⌈来大碗拉面加个蛋⌉,服务员拿纸记录下来
$buf = socket_read($client, 1024);
处理信号,后厨阅读纸片,制片内容如下
$content = 'hello! i am server!';
$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;
向客户端写入信号,上菜品
socket_write($client,$http_resonse);
关闭客户端,资源回收。系统创建的资源描述符是有限的(因为每个资源描述符都要打开输入输出缓冲区,如果不及时回收资源,内存就会被占满)
socket_close($client);
关闭服务端,店面关门
socket_close($server);
处理信号
上边读取到客户端的信号buf,如果我请求的地址是这样:
打印buf:
buf是一长串字符串,用正则来匹配该字符串:
$preg = '#GET (.*) HTTP/1.1#iU';
preg_match($preg, $buf, $arr);
$request = $arr[1];
匹配的 (.*)
是:
这样我们就拿到了请求的内容。
响应
如果是加载静态页面:
获取的文件名是
那么 $response
是:
$filePath = __DIR__ . '/html' . $path;
$content = file_get_contents($filePath);
如果是 php
文件:
获取的文件名是:
那么 $response
是:
$filePath = __DIR__ . '/php' . $path;
ob_start();
include $filePath; //这里执行了一段php逻辑代码
$content = ob_get_contents();
ob_clean();
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: