<?php
//============================================================
//-------------------------HTTP-------------------------------
/* 
webservice = http协议 + XML
Rest = HTTP协议 + json
...

协议有 ftp http stmp pop tcp/ip 等
 */
//------------------------------------------------------------
//---------------HTTP请求信息和响应信息的格式----------------
/* 
请求:

1.请求行
	(1)请求方法 GET POST HEAD PUT DELETE TRACE OPTIONS
	(2)请求路径 http.php
	(3)所用协议 HTTP/1.1
2.请求头信息
	Host: localhost
3.请求主体信息
	注意:头信息和主体信息要空一行


响应:

1.响应行
	(1)协议版本 HTTP/1.1 200 OK
	(2)状态码   200
	(3)状态文字 OK
2.响应头信息
	健名:健值
	key:value
	Content-Length:12
3.响应主体信息
 */
//------------------------------------------------------------
//-----------------DOS窗口发送HTTP请求方法-------------------
/* 
1. ipconfig命令查看本机IP
	IPv4 地址 . . . . . . . . . . . . : 192.168.1.101
2. telnet 192.168.1.101 80   打开80端口
3. 用 ctrl + ] 再回车  打开回显功能
4. 输入如下内容:
	GET /http.php HTTP/1.1
	Host: localhost
	Content-length: 23
	
	username=admin&pass=123
	(两次回车)
	
	然后可看到如下的请求信息
	HTTP/1.1 200 OK
	Date: Fri, 04 Mar 2016 06:56:41 GMT
	Server: Apache/2.4.10 (Win32) OpenSSL/0.9.8zb mod_fcgid/2.3.9
	X-Powered-By: PHP/5.4.33
	Transfer-Encoding: chunked
	Content-Type: text/html
	
	ok这是返回的信息
	
5.post请求时请求头信息中要加
	Content-type: application/x-www-form-urlencoded
	
	示例:
	POST /http.php HTTP/1.1
	Host: localhost
	Content-type: application/x-www-form-urlencoded
	Content-length: 25
	
	demo=admin1&test=ppppoopp
	
问题解决:
“telnet 不是内部命令” 解决方法:
控制面板->程序->打开或关闭Windows功能,勾上telnet客户端
 */
//------------------------------------------------------------
//--------------------常见请求方法解释-----------------------
/* 
HEAD	查看请求的地址是否正常
PUT		向服务器传输内容
TRACE	代理访问时查看是否修改请求
OPTION	查看服务器允许的请求方法
 */
//------------------------------------------------------------
//--------------------常见状态码解释-------------------------
/* 
1XX		接收到请求继续处理(预留扩展使用)
2XX		成功
3XX		重定向
4XX		客户端错误
5XX		服务器端错误

200 	服务器返回网页
301/302	永久/临时重定向
		永久重定向:
		header('Location:http://www.chuxiangyi.com',true,301);
		
304		Not Modified 未修改(取缓存)
		文件比对信息,缓存是否被修改,请求头信息中添加
		If-Modified-Since:Fri, 26 Feb 2016 07:46:08 GMT
		If-None-Match:"3000652404"

307		重定向中保持原有的数据(防止post请求时数据丢失)
		header('Location:http://www.chuxiangyi.com',true,307);
		
404		请求页面不存在
503		服务器暂时不可以
500		服务器内部错误
 */
//------------------------------------------------------------
//-------------------PHP + socket请求原理---------------------
/* 
$fp = fsockopen('192.168.1.101',80, $errno, $errstr, 30);
if (!$fp){
	echo "$errstr ($errno)<br />\n";
}else{
	$out = "GET /demo.php HTTP/1.1\r\n";
	$out .= "Host: localhost\r\n";
	$out .= "Connection: Close\r\n\r\n";
	fwrite($fp, $out);
	while (!feof($fp)){
		echo fgets($fp, 128);
	}
	fclose($fp);
}
 */
//------------------------------------------------------------
//------------------------------------------------------------

示例:

<?php
class web_config {
    // 监听的端口号
    const PORT = 9003;
    // 项目根目录
    const WEB_ROOT = "/var/www/html";
}


class server {
    private $ip;
    private $port;
    public function __construct($ip, $port) {
        $this->ip = $ip;
        $this->port = $port;
        $this->await();
    }
    private function await() {
        $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if ($sock < 0) {
            echo "Error:" . socket_strerror(socket_last_error()) . "\n";
        }
        $ret = socket_bind($sock, $this->ip, $this->port);
        if (!$ret) {
            echo "BIND FAILED:" . socket_strerror(socket_last_error()) . "\n";
            exit;
        }
        echo "OK\n";
        $ret = socket_listen($sock);
        if ($ret < 0) {
            echo "LISTEN FAILED:" . socket_strerror(socket_last_error()) . "\n";
        }
        do {
            $new_sock = null;
            try {
                $new_sock = socket_accept($sock);
            } catch (Exception $e) {
                echo $e->getMessage();
                echo "ACCEPT FAILED:" . socket_strerror(socket_last_error()) . "\n";
            }
            try {
                $request_string = socket_read($new_sock, 1024);
                $response = $this->output($request_string);
                socket_write($new_sock, $response);
                socket_close($new_sock);
            } catch (Exception $e) {
                echo $e->getMessage();
                echo "READ FAILED:" . socket_strerror(socket_last_error()) . "\n";
            }
        } while (TRUE);
    }
    /**
     * @param $request_string
     * @return string
     */
    private function output($request_string){
        // 静态 GET /1.html HTTP/1.1 ...
        $request_array = explode(" ",$request_string);
        if(count($request_array) < 2){
            return $this->not_found();
        }
        $uri = $request_array[1];
        $filename = web_config::WEB_ROOT . $uri;
        echo "request:".$filename."\n";
        // 静态文件的处理
        if (file_exists($filename)) {
            return $this->add_header(file_get_contents($filename));
        } else {
            return $this->not_found();
        }
    }
    /**
     * 404 返回
     * @return string
     */
    private function not_found(){
        $content = "<h1>File Not Found </h1>";
        return "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html\r\nContent-Length: ".strlen($content)."\r\n\r\n".$content;
    }
    /**
     * 加上头信息
     * @param $string
     * @return string
     */
    private function add_header($string){
        return "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($string)."\r\nServer: mengkang\r\n\r\n".$string;
    }
}
$server = new server("0.0.0.0", web_config::PORT);