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

来源:互联网 发布:宝鸡文理学院网络课程 编辑:程序博客网 时间:2024/05/21 14:03

回顾前面: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.1Host: 127.0.0.1:9090Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-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.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip, deflate, sdch, brAccept-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协议有所帮助。

0 0
原创粉丝点击