zoukankan      html  css  js  c++  java
  • 用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
        );
    }
  • 相关阅读:
    MVP社区巡讲照片集
    周末之个人杂想(十六)
    SQL Server 2014 BI新特性(二)结合Data Explorer和GeoFlow进行数据分析
    SQL Server 2014 BI新特性(一)五个关键点带你了解Excel下的Data Explorer
    Tabular Model下的ADOMD.NET
    玩玩Excel下的Power View
    LeakCanary,30分钟从入门到精通
    Android热修复技术总结
    阿里最新热修复Sophix与QQ超级补丁和Tinker的实现与总结
    热修复——深入浅出原理与实现
  • 原文地址:https://www.cnblogs.com/eastson/p/2796276.html
Copyright © 2011-2022 走看看