PHP Socket编程 之 php实现http服务

http服务是建立在tcp服务之上的,它是tcp/ip协议的应用,前面我们已经实现了tcp服务,并且使用三种不同的方式连接tcp服务

既然http也是tcp应用层的一种,那么我们直接使用浏览器来连接tcp服务可不可以?答案是可以的,只不过连接之后直接返回给浏览器的信息,浏览器不能够正确的识别出来。那么怎么才能让浏览器正确的识别tcp服务返回的信息呢?

这个时候我们就需要使用到http协议啦,至于http传输中都传了哪些信息可以在浏览器中 f12 查看

http_serv.php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<?php
/**
* Http 服务器类
*/
class Http{
    private $host;
    private $port;
    private $_root;
 
    public $mime_types = array(
        'avi' => 'video/x-msvideo',
        'bmp' => 'image/bmp',
        'css' => 'text/css',
        'doc' => 'application/msword',
        'gif' => 'image/gif',
        'htm' => 'text/html',
        'html' => 'text/html',
        'ico' => 'image/x-icon',
        'jpe' => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'jpg' => 'image/jpeg',
        'js' => 'application/x-javascript',
        'mpeg' => 'video/mpeg',
        'ogg' => 'application/ogg',
        'png' => 'image/png',
        'rtf' => 'text/rtf',
        'rtx' => 'text/richtext',
        'swf' => 'application/x-shockwave-flash',
        'wav' => 'audio/x-wav',
        'wbmp' => 'image/vnd.wap.wbmp',
        'zip' => 'application/zip',
      );
 
    /**
     * @param string $host 监听地址
     * @param int $port 监听端口
     * @param string $_root 网站根目录
    */
    public function __construct($host,$port,$_root){
        $this->host = $host;
        $this->port = $port;
        $this->_root = $_root;
    }
 
    /**
    * 启动http服务
    */
    public function start(){
        //创建socket套接字
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        //设置阻塞模式
        socket_set_block($socket);
        //为套接字绑定ip和端口
        socket_bind($socket,$this->host,$this->port);
        //监听socket
        socket_listen($socket,4);
 
        while(true)
        {
            //接收客户端请求
            if(($msgsocket = socket_accept($socket)) !== false){
                //读取请求内容
                $buf = socket_read($msgsocket, 9024);
                 
                preg_match("/\/(.*) HTTP\/1\.1/",$buf,$matchs);
                 
                preg_match("/Accept: (.*?),/",$buf,$matchss);
                //获取接收文件类型
                $type = explode("/",$matchss[1])[0];
 
                if($type=="text"){
                    $content = $this->GetString($matchs[1]);
                }else{
                    $content = $this->GetImg($matchs[1]);
                }
 
                socket_write($msgsocket,$content,strlen($content));
 
                socket_close($msgsocket);
            }
        }
    }
 
    /**
     * 组装消息头信息模板
     * @param int $code 状态码
     * @param string $status 状态名称
     * @param string $content 发送的文本内容
     * @param string $content_type 发送的内容类型
     * @return string
    **/
    public function GetHeaders($code,$status,$content="",$content_type="text/html;charset=utf-8"){
        $header = '';
        $header .= "HTTP/1.1 {$code} {$status}\r\n";
        $header .= "Date: ".gmdate('D, d M Y H:i:s T')."\r\n";
        $header .= "Content-Type: {$content_type}\r\n";
        $header .= "Content-Length: ".strlen($content)."\r\n\r\n";//必须2个\r\n表示头部信息结束
        $header .= $content;
        return $header;
    }
 
    /**
    * 组装文本发送信息
     * @param string $url_path
     * @return string
    **/
    public function GetString($url_path){
        if($this->getRealPath($url_path)){
            if(is_readable($this->getRealPath($url_path))){
                return $this->GetHeaders(200,"OK",file_get_contents($this->getRealPath($url_path)),$this->getMime($url_path));
            }else{
                return $this->GetHeaders(401,"Unauthorized");
            }
             
        }else{
            return $this->GetHeaders(404,"Not Found");
        }
    }
 
    /**
    * 组装资源返回信息
     * @param string $url_path
     * @return string
    **/
    public function GetImg($url_path){
        if($this->getRealPath($url_path)){
 
            return $this->GetHeaders(200,"OK",file_get_contents($this->getRealPath($url_path)),$this->getMime($url_path));
        }else{
           return $this->GetHeaders(404,"Not Found");
        }
    }
 
    /**
     * 获取资源类型
     * @param string $path
     * @return mixed
     */
    public function getMime($path){
       $type = explode(".",$path);
       $mime = $this-> mime_types[$type[1]];
       return $mime;
    }
 
    /**
     * 获取访问资源的真实地址
     * @param $url_path
     * @return bool|string
     */
    public function getRealPath($url_path){
        return realpath($this->_root."/".$url_path);
    }
 
}
 
$server = new Http("127.0.0.1",3046,"wwwroot");
$server->start();

效果图:

 

github地址: https://github.com/enjoysmilehappy/http_server

链接:https://www.cnblogs.com/itsuibi/p/11139112.html

posted @   笠航  阅读(268)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示