用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

    );

}

你可能感兴趣的:(server)