Socket学习 - 从这个角度学http协议就很简单了

回顾前面: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协议有所帮助。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值