回顾前面:Socket学习 - 开启Socket学习之旅
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); // 购买电话机
socket_bind($socket,'127.0.0.1',9090); // 绑定电话机
socket_listen($socket,5); // 开机
while(true){
$client = socket_accept($socket); // 有人打电话进来
$buf = socket_read($client,1024); // 一次读取1024的长度
echo $buf;
// 回复
socket_write($client,'hello socket');
socket_close($client); // 关掉客户端
}
socket_close($socket); // 关机
我们服务端server.php代码中echo $buf;
会输出HTTP协议的部分内容。
注意:是要浏览器访问的情况下,因为浏览器走了HTTP协议的。
同时我们也可以看到,虽然浏览器是通过HTTP协议的,但我们服务端并不用也遵守这个协议。
本节,我们就在socket来模拟一下HTTP协议。
1.先在项目下新建个html文件,便于我们测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是静态新闻首页的内容
</body>
</html>
然后我们浏览器这样访问:http://127.0.0.1:9090/news/index.html
2.我们在服务端server.php里来查看浏览器访问时,发送过来的数据。
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); // 购买电话机
socket_bind($socket,'127.0.0.1',9090); // 绑定电话机
socket_listen($socket,5); // 开机
while(true){
$client = socket_accept($socket); // 有人打电话进来
$buf = socket_read($client,1024); // 一次读取1024的长度
echo $buf;
if(preg_match("/GET\s\/(.*?)\sHTTP\/1.1/i",$buf,$matches)){
var_export($matches);
}
// 回复
socket_write($client,'hello socket');
socket_close($client); // 关掉客户端
}
socket_close($socket); // 关机
我们已经知道上面代码中echo $buf
就能读取到浏览器发送过来的HTTP内容,如下:
GET /news/index.html HTTP/1.1
Host: 127.0.0.1:9090
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
然后我们用正则匹配这部分内容,var_export($matches);
打印如下:
array (
0 => 'GET /news/index.html HTTP/1.1',
1 => 'news/index.html',
)
3.根据浏览器的请求,服务端回复内容
server.php
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); // 购买电话机
socket_bind($socket,'127.0.0.1',9090); // 绑定电话机
socket_listen($socket,5); // 开机
while(true){
$client = socket_accept($socket); // 有人打电话进来
$buf = socket_read($client,1024); // 一次读取1024的长度
echo $buf;
if(preg_match("/GET\s\/(.*?)\sHTTP\/1.1/i",$buf,$matches)){
$page_path = $matches[1]; // 文件在本地的路径
if(file_exists($page_path)){
$html_content = file_get_contents($page_path); //读取文件内容
//socket回复给客户端
socket_write($client,$html_content);
}else{
socket_write($client,'404');
}
}else{
// 回复
socket_write($client,'hello socket');
}
socket_close($client); // 关掉客户端
}
socket_close($socket); // 关机
可以看到服务端确实把news\index.html
的内容返回给了浏览器。
4.回复复合要求的内容
我们已经把html文件的里的内容读取出来,并成功回复(响应到浏览器上了),但并不是我们理想的效果,原因就在于:我们并没有严格按照HTTP的协议响应数据给浏览器。
在socket_write
回复的数据,需要按照HTTP定义的格式来。
看代码:
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); // 购买电话机
socket_bind($socket,'127.0.0.1',9090); // 绑定电话机
socket_listen($socket,5); // 开机
while(true){
$client = socket_accept($socket); // 有人打电话进来
$buf = socket_read($client,1024); // 一次读取1024的长度
echo $buf;
if(preg_match("/GET\s\/(.*?)\sHTTP\/1.1/i",$buf,$matches)){
$page_path = $matches[1]; // 文件在本地的路径
if(file_exists($page_path)){
//拼接HTTP响应格式
$html_content = 'HTTP/1.1 200 OK'.PHP_EOL
.'Content-Type: text/html;'.PHP_EOL
.PHP_EOL
.file_get_contents($page_path);
//socket回复给客户端
socket_write($client,$html_content);
}else{
socket_write($client,'404');
}
}else{
// 回复
socket_write($client,'hello socket');
}
socket_close($client); // 关掉客户端
}
socket_close($socket); // 关机
然后浏览器访问http://127.0.0.1:9090/news/index.html
:
这样才是html文件在浏览器上的正确姿势。
希望从这个案例上,对理解HTTP协议有所帮助。