• 用PHP实现Web Server


    以前做的一个例子,用PHP模拟Web服务器和客户端。年初的时候网站数据丢失,重新补传一次。

    服务端代码server.php:

    <?php
    
    $host = '127.0.0.1';
    $port = 9083;
    
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if ($socket === FALSE)
    {
        display_socket_error();
    }
    
    if (socket_bind($socket, $host, $port) === FALSE)
    {
        display_socket_error();
    }
    
    if (socket_listen($socket, 3) === FALSE)
    {
        display_socket_error();
    }
    
    while (true)
    {
        $csocket = socket_accept($socket);
        if ($csocket === FALSE)
        {
            display_socket_error();
        }
        
        $request = parse_socket_request($csocket);
        print_r($request);
        
        if (strcasecmp($request['uri'], '/quit') === 0)
        {
            socket_close($csocket);
            break;
        }
        
        handle_request($csocket, $request);
        socket_close($csocket);
    }
    
    socket_close($socket);
    
    function display_socket_error()
    {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        die("Socket error: [$errorcode] $errormsg");
    }
    
    function parse_socket_request($socket)
    {
        $result = socket_read($socket, 4096, PHP_BINARY_READ);
        if ($result === FALSE)
        {
            display_socket_error();
        }
        
        $lines = explode("\r\n", $result);
        
        list($method, $uri, $protocol) = explode(" ", $lines[0], 3);
        
        $headers = array();
        for ($i = 1; $i < count($lines); $i++)
        {
            if ($lines[$i] === "")
                break;
            $parts = explode(":", $lines[$i], 2);
            $headers[trim($parts[0])] = trim($parts[1], " \"");
        }
        
        $body = '';
        for ($i = $i + 1; $i < count($lines); $i++)
        {
            $body .= $lines[$i] . "\r\n";
        }
        
        return array('protocol' => $protocol,
                'uri' => $uri,
                'method' => $method,
                'headers' => $headers, 
                'body' => $body
        );
    }
    
    function send_response_line($socket, $line)
    {
        if (socket_write($socket, $line, strlen($line)) === FALSE)
        {
            display_socket_error();
        }
    }
    
    function handle_request($socket, $request)
    {
        $abs_path = realpath(dirname(__FILE__) . '/../' . $request['uri']);
        
        if (is_file($abs_path))
        {
            send_response_content($socket, $abs_path, 200, "OK");
            return;
        }
        
        if (is_dir($abs_path))
        {
            $index_file = $abs_path . DIRECTORY_SEPARATOR . 'index.html';
            if (is_file($index_file))
            {
                send_response_content($socket, $index_file, 200, "OK");
                return;
            }
        }
        
        send_response_404($socket);
    }
    
    function send_response_content($socket, $path, $statusCode, $statusText)
    {
        $mimetype = get_content_type($path);
        $content = file_get_contents($path);
        
        send_response_line($socket, "HTTP/1.1 " . $statusCode . " " . $statusText . "\r\n");
        send_response_line($socket, "Server: PHPSocketServer\r\n");
        send_response_line($socket, "Accept-Ranges: bytes\r\n");
        send_response_line($socket, "Content-Type: " . $mimetype . "\r\n");
        send_response_line($socket, "Content-Length: " . strlen($content) . "\r\n");
        send_response_line($socket, "\r\n");
        send_response_line($socket, $content);    
    }
    
    function send_response_404($socket)
    {
        send_response_content($socket, realpath(dirname(__FILE__) . '/error404.html'), 404, 'Not Found');
    }
    
    function get_content_type($path)
    {
        $mimetypelist["gif"] = "image/gif";
        $mimetypelist["jpeg"] = "image/jpeg";
        $mimetypelist["jpg"] = "image/jpeg";
        $mimetypelist["jpe"] = "image/jpeg";
        $mimetypelist["png"] = "image/png";
        $mimetypelist["tiff"] = "image/tiff";
        $mimetypelist["tif"] = "image/tiff";
        $mimetypelist["bmp"] = "image/x-ms-bmp";
        $mimetypelist["html"] = "text/html";
        $mimetypelist["htm"] = "text/html";
        $mimetypelist["txt"] = "text/plain";
    
        $ext = pathinfo($path, PATHINFO_EXTENSION);
        if (isset($mimetypelist[$ext]))
            return $mimetypelist[$ext];
        else
            return '';
    }

    客服端代码client.php:

    <?php
    
    $host = '127.0.0.1';
    $port = 9083;
    
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if ($socket === FALSE)
    {
        display_socket_error();
    }
    
    if (socket_connect($socket, $host, $port) === FALSE)
    {
        display_socket_error();
    }
    
    echo "Connection successful on IP $host, port $port\r\n\r\n\r\n";
    
    send_request_line("GET /abc.txt HTTP/1.1\r\n");
    send_request_line("Host: localhost\r\n");
    send_request_line("\r\n");
    
    $response = parse_socket_response();
    print_r($response);
    
    socket_close($socket);
    
    function send_request_line($line)
    {
        global $socket;
        if (socket_write($socket, $line, strlen($line)) === FALSE)
        {
            display_socket_error();
        }
    }
           
    function display_socket_error()
    {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        die("Socket error: [$errorcode] $errormsg");
    }
    
    function parse_socket_response()
    {
        global $socket;
        
        $result = socket_read($socket, 4096, PHP_BINARY_READ);
        if ($result === FALSE)
        {
            display_socket_error();
        }
        
        /*
        返回的响应信息如下:
        HTTP/1.1 200 OK
        Date: Wed, 27 Jul 2011 01:49:49 GMT
        Server: Apache/2.2.15 (Win32) mod_ssl/2.2.15 OpenSSL/0.9.8n
        Last-Modified: Tue, 26 Jul 2011 05:57:42 GMT
        ETag: "200000006a2ae-16-4a8f29c2a18a6"
        Accept-Ranges: bytes
        Content-Length: 22
        Content-Type: text/plain
        
        This is a server file.    
        
        每一行都以\r\n作为结尾。
        
        响应信息可以分为三个部分:
        1. 第一行是响应行,以空格分割,依次是协议,状态码和状态说明。
        2. 响应头,在响应信息中以一个空行分割。名称和值以冒号分开。
        3. 内容,在响应信息的最后面。
        */
        
        $lines = explode("\r\n", $result);
        
        list($protocol, $statusCode, $statusText) = explode(" ", $lines[0], 3);
        
        $headers = array();
        for ($i = 1; $i < count($lines); $i++)
        {
            if ($lines[$i] === "")
                break;
            $parts = explode(":", $lines[$i], 2);
            $headers[trim($parts[0])] = trim($parts[1], " \"");
        }
        
        $body = '';
        for ($i = $i + 1; $i < count($lines); $i++)
        {
            $body .= $lines[$i] . "\r\n";
        }
        
        return array('protocol' => $protocol,
                'statusCode' => $statusCode,
                'statusText' => $statusText,
                'headers' => $headers, 
                'body' => $body
        );
    }
  • 相关阅读:
    mysql不停库不锁表在线主从配置
    MySQL5.7不停机不锁表主从同步实战
    另类 k8s 集群灾难恢复方法:用 master 服务器镜像恢复出新集群
    我在新西兰卖挖掘机之续篇十八------坚持的秘诀(坚持的秘诀就2条,第一是初始摩擦力要足够小(开头不能太困难,时间不能太久);第二是坚持的事情能够不断地给你提供某种真实的好处)(其实就是正反馈,加上一点点兴趣)
    分布式系统中那些不靠谱任务-CAP 到底是什么
    分布式系统架构中关于切分数据库事务的 ACID 性质的可用性与性能-BASE 理论和CAP 定理
    SSO协议-SAML和OAuth2
    领域建模
    基于 Docker 容器Net Core微服务部署 Nginx 集群架构
    消息队列和分布式锁
  • 原文地址:https://www.cnblogs.com/eastson/p/2796276.html
Copyright © 2020-2023  润新知