IT编程PHP

PHP 网络技术

2017-02-15  本文已影响293人  单板小智

HTTP协议详解

HTTP协议是一个应用层的通信规范: 双方要进行通信, 大家都要遵守一个规范——HTTP协议。HTTP协议从WWW服务器传世超文本到浏览器, 可以使浏览器更加高效。

HTTP(Hyper Text Transfer Protocol, 超文本传输协议)万维网协会(Word Wide Web Consortium)Internet 工作小组(Internet Engineering Task Force, IETF) 合作的结果, 最终发布了一些列的RFC(Request For Comments)RFC 1945定义了HTTP 1.0版本, 最著名的RFC 2616, 其中定义了目前普遍使用的版本——HTTP1.1。

HTTP是一个应用层协议, 由请求和响应构成, 是一个标准的客户端服务器模型。HTTP通常承载于TCP协议之上, 也有时候承载在TLS或SSL协议层之上, 这个时候就成了常说的HTTPS。

HTTP默认端口为80, HTTPS的端口是443。

HTTP协议是一个无状态的协议, 同一个客户端的这次请求和上次请求没有对应关系。

sequenceDiagram
Client->>Server: 请求
Server->>Client: 响应

这种设计属于问答式交互, 客户端和服务器一问一答, 使HTTP协议模型异常简单。但是这种设计也存在一些问题, 例如服务端不会主动向客户端PUSH, 一问一答的轮询也会使TCP连接频繁建立和断开, 导致其交互效率不高。基于上面缺点, SPDY协议诞生了。

SPDY 协议由谷歌推出, 优化浏览器和服务器之间的通信, 支持流复用, 具备优先级的请求、主动发起请求、强制SSL安全传输等先进特性。

目前Chrome 和 Firefox浏览器的最新版本都支持 SPDY, 一些服务端软件支持SPDY, 如Jetty 8、Nginx 1.3.x等。

SPDY 协议的应用需要客户端浏览器和服务端同时支持。 目前应用SPDY 协议主要是Google的产品, 如Google Plus。

HTTP 协议如何工作

浏览网页是HTTP协议的主要应用, 但是不代表HTTP协议只能用于网页的浏览。只要通信的双方都遵守HTTP协议, 就有用武之地。

HTTP协议如何工作:

首先, 客户端发送一个请求(Request) 给服务器, 服务器在接收到这个请求后将生成一个响应(Response)返回给客户端。一次HTTP操作称之为一个事务, 其工作过程可分为四步:

关于HTTP协议, 可以查看RFC 2616文档。

常用的抓包软件有IRIS、Wireshark等。

下面介绍HTTP协议中的一些主要的概念

在发起请求前, 需要先建立连接。

连接是一个传输层的实际环流, 它建立在两个相互通信的应用程序之间。

HTTP 1.1协议中, Request 和 Response 头中都可能出现一个 connection 的头, 其决定 Client和Server通信时对于长链接如何处理。

HTTP 1.1 中, Client和Server默认对方支持长链接, 如果CLient不希望使用长链接, 需要在Header中指明connection 为 cliose; 如果Server 不想支持长链接, 则在response中需要明确说明connection 为close。

在接收和解释请求消息后, 服务器返回一个HTTP响应消息。HTTP响应也由三个部分组成: 状态行、消息报头、响应正文。

状态码由三位数字组成, 第一个数字定义了响应的类别, 有五种可能取值:

1xxx: 指示信息——请求已被成功接收, 继续处理
2xx: 成功——请求已被成功接收、理解、接受
3xx: 重定向——要完成请求必须进行更进一步的操作
4xx: 客户端错误——请求有语法错误或请求无法实现
5xx: 服务器端错误——服务器未能实现合法请求

HTTP消息报头包括普通报头、请求报头、响应报头、实体报头

  1. 普通报头中有少数报头域用作所有的请求和响应消息, 但并不用作于被传输的实体, 只用于传输的消息(如缓存控制、连接控制等)
  2. 请求报头允许客户端向服务端传递请求的附加信息以及客户端自身的信息(如UA头、Accept等)
  3. 响应报头允许服务器传递不能放在状态行中的附加响应信息, 以及关于服务器的信息和对 Request-URI 所标识的资源进行下一步访问的信息(如Location)。
  4. 实体报头定义了关于实体正文和请求所标识的资源的元信息, 例如有无实体正文。

比较重要的几个报头如下:

PHP中一系列与HTTP协议相关的一系列函数:

简单的HTTP协议使用示例

<?php
$html = file_get_contents('http://www.baidu.com/');
print_r($http_response_header);
$fp = fopen('http://www.baidu.com/', 'r');
print_r(stream_get_meta_data($fp));
fclose($fp);

context 参数使这些函数更加灵活, 通过该参数可以定制HTTP请求, 设置POST数据。

<?php
$data = array('author' => 'pchangl', 'mail' => 'pchangl@163.com', 'text' => 'test content.');
$data = http_build_query($data);
$opts = array(
    'http' => array(
        'method' => 'POST',
        'header' => 'Content-type:application/x-www-form-urlencoded\r\n' .
            'Content-Length:' . strlen($data) . "\r\n",
        'content' => $data
    )
);

$context = stream_context_create($opts);
$html = @file_getcontents('http://www.baidu.com/', false, $context);

垃圾信息防御措施

Socket进程通信机制

Socket 通常称为套接字, 用于描述IP地址和端口, 是一个通信链的句柄。应用程序通过套接字向网络发出请求或者应答网络请求。Socket既不是一个程序, 也不是一种协议, 只是操作系统提供的通信层的一组抽象API。

进程通信相关概念

为保证两个相互通信的进程之间即互不干扰又协调一致工作, 操作系统为进程通信提供了相应措施, 如UNIX BSD中的管道(pipe)、命名管道(named pipe)和软中断信号(signal), 以及UNIX System V的消息(message)、共享存储区(shared memory)和信号量(semaphore)等, 但这些都仅限于在本机进程之间的通信。

操作系统支持网络协议众多, 不同协议工作方式不同, 地址格式也不同, 因此, 网间通信还要解决多重协议的识别问题。

为了解决上述问题, TCP/IP协议引入了下列概念。

网络中可以被命名和寻址的通信端口, 是操作系统可分配的一种资源。

端口是一种软抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序(即进程)通过系统调用某端口建立连接后, 传输层给该端口的数据都被相应进程所接收, 相应进程发给传输层的数据都通过该端口输出。

TCP和UDP协议完全是两个独立的两个软件模块, 因此各自端口号也相互独立, TCP有一个255号端口, UDP也有一个255端口号, 二者并不冲突。TCP和UDP都有0~65535个端口号

常见的端口有FTP的21号端口, HTTP服务的80端口, SMTP的25端口和HTTPS的443端口。

网络通信中通信的两个进程分别处在不同的机器上。遵循以下原则:

两个进程间的通信链路称为连接, 连接表现为一些缓冲区和一组协议机制。

SOCKET socket(int af, int type, int protocol);

  1. 流套接字类型(SOCK_STREAM): 最常见的类型, 基于TCP协议
  2. 数据报套接字类型(SOCK_DGRAM): 即UDP数据报
  3. 原始套接字类型(SOCK_RAW): 在IP层对套接字进行编程, 实际上就是在IP层构造自己的IP包, 然后把这个包发出去
php中的socket函数

cURL 工具及应用

建立cURL请求的基本步骤:

<?php
// 1. 初始化
$ch = curl_init();
// 2. 设置选项, 包括URL
curl_setopt($ch, CURLOPT_URL, "http://www.php.net");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    //将curl_exec() 获取的信息以文件流的形式返回,
                                                // 而不是直接输出
curl_setopt($ch, CURLOPT_HEADER, 1);            //启用时会将头文件的信息作为数据流输出

// 3. 执行并获取 HTML 文档内容
$output = curl_exec($ch);
// 4. 释放cURL句柄
curl_close($ch);
echo $output;

cURL 常用选项

选项 描述
CURLOPT_AUTOREFERER 当根据Location 重定向时, 自动设置 header 中的 Referer 信息
CURLOPT_COOKIESESSION 启用时 cURL 会仅仅传递一个 Session Cookie, 忽略其他 Cookie, 默认情况下 cURL 会将所有 Cookie 返回给服务器。Session Cookie 指用来判断服务端的 Session 是否有效而存在的 Cookie
CURLOPT_FOLLOWLOCATION 启用将服务器返回的 Location 放在 Header 中, 递归的返回给服务器, 使用 CURLOPT_MAXREDIRS 可以限定递归返回的树立
CURLOPT_HEADER 启用时将头文件的信息作为数据流输出
CURLOPT_RETURNTRANSFER 将 curl_exec() 获取的信息以文件流的形式返回, 而不是直接输
CURLOPT_INFILESIZE 设定上传文件的大小, 单位为字节(byte)
CURLOPT_MAXCONNECTS 运行最大连接数量, 超过会通过CURLOPT_CLOSEPOLICY 决定应该停止哪些连接
CURLOPT_MAXREDIRS 指定 HTTP 重定向的最多数量, 和 CURLOPT_FOLLOWLOCATION 一起使用
CURLOPT_COOKIE 设定 HTTP 请求中 Cookie 部分的内容, 多个 Cookie 用分号分隔, 分号后带一个空格
CURLOPT_COOKIEFILE 包含 Cookie 数据的文件名, Cookie 文件的格式可以是 Netscape 格式, 或者只是纯 HTTP 头部信息存入文件
CURLOPT_ENCODING HTTP 请求头中 Accept-Encoding 的值, 支持的编码有 identity, deflate 和 gzip。如果空字符串"", 请求头会发送所有支持的编码类型
CURLOPT_POSTFIELDS 全部数据使用 HTTP 协议中的 POST 操作来发送。 要发送文件, 在文件名前面加上@前缀并使用完整路径。这个参数通过 urlencoded 后的字符串类似 paral=val1&para2=varl2&... 或使用一个一字段名为键, 字段数据为值的数组。如果value是一个数组, Content-type 头会被设置成 multipart/form-data
CURLOPT_RANGE 以 X-Y 的形式组成, 其中 X 和 Y 都是可选项获取数据的范围, 单位是字节。 HTTP 传输线程也支持几个这样的重复项中间用逗号分隔如 X-Y,N-M
CURLOPT_REFERER HTTP 请求中 Referer 的内容
CURLOPT_HTTPHEADER 用来设置 HTTP 头字段的数组。数组形式如下: array('Content-type: text/plain', 'Content-length: 100')
CURLOPT_FILE 设置输出文件的位置, 值是一个资源类型, 默认为 STDOUT(浏览器)
CURLOPT_INFILE 在上传文件时需要读取的文件地址, 值是一个资源类型
CURLOPT_HEADERFUNCTION 设置一个回调函数, 其有两个参数: 第一个是 cURL 的资源句柄, 第二个是输出的 hander 数据。header 数据的输出必须依赖这个函数, 返回写入的数据大小
CURLOPT_WRITEFUNCTION 拥有两个参数的回调函数: 第一个参数是会话句柄, 第二个是 HTTP 响应头信息的字符串。使用此回调函数, 将自行处理响应头信息。响应头信息是整个字符串。设置返回值为精确的已写入字符串长度。发生错误时传输线程终止

PHPRPC 协议

一个轻型的、安全的、跨网际、跨语言的、跨平台的、跨环境的、跨域的协议, 支持复杂对象传输、引用参数传递、内容输出重定向、分级错误处理、会话,是面服务的高性能远程过程调用协议。

PHPRPC 官网: http://phprpc.org/zh_CN/

PHPRPC 作为客户端

<?php
include ("phprpc/phprpc_client.php");
$client = new PHPRPC_Client('http://library.aiyooyoo.com:8080/action/book/rpc.jsp');
echo $client->say('白菜');
echo $client->allcount();
echo $client->findbooks(0,5);

PHPRPC 作为服务端

<?php
include ("phprpc/phprpc_server.php");

class Hello
{
    static function HelloWorld()
    {
        return 'Hello World';
    }
}

$server = new PHPRPC_Server();
$server->add('HelloWorld', 'hello');
$server->start();

PHPRPC 客户端调用上面服务端

<?php

include ("phprpc/phprpc_client.php");
$client = new PHPRPC_Client('http://127.0.0.1/php/rtest.php');
echo $client->HelloWorld();

SOAP

Cookie

Cookie 是在远程浏览器端存储数据并以此跟踪和识别用户的机制。Cookie 是存储在客户端上的一小段数据, 浏览器(客户端) 通过 HTTP 协议和服务器进行 Cookie 交互。

关于 Cookie 的 RFC 文档主要有: RFC 6265、 RFC 2109

Cookie 主要是参照 RFC2019 标准由客户端实现其生成、使用整个管理过程, 服务端则参照此标准实现和客户端之间的交互指令。

Cookie 是 HTTP 头的一部分, 即先发送或请求Cookie, 接下来才是data 域,所以setcookie() 等函数必须在其输出数据之前调用, 这和 header() 函数是相同的。也可以使用输出缓冲函数延迟脚本的输出, 直到设置好所有 Cookie 和其他 HTTP 标头。

Cookie 跨域与P3P协议

正常 Cookie 只能在一个应用中共享, 即一个 Cookie 只能由创建它的应用获得。实现 Cookie 的跨域, 主要是为了统一应用平台, 即实现目前流行的单点登录。最简单的方式就是使用 P3P 协议。

P3P(Platform for Prvacy Preferences) 协议由万维网协会研制, 为 Web 用户提供了对自己公开信息的更多控制。

如果是多个工程, 其间关系就变得非常复杂, 这个时候, 就需要一个完整的 SSO 方案, 通常是通过 SSO Server 系统进行中转, CAS 就是一个成熟的 SSO 解决方案。而不是使用跨域 Cookie。

本地存储 localStorage

一个域名的每个 Cookie 限制在4千字节键值对的形式存在, 如果要在本地存储数据, 可以使用localStorage本地存储。

//检测浏览器是否支持 localStorage
if (window.localStorage) {
    alert('This browser supports localStorage');
} else {
    alert('This browser does not support localStorage');
}

HTML 5 本地存储只能存储字符串, 任何格式存储的时候都会被自动转化为字符串, 所以读取的时候, 需要自己进行类型转换。

HTML 5 监听 storage 键值对改变事件:

if (window.AddEventListener) {
    window.addEventListener("storage", handle_storage, false);
} else if(window.attachEvent) {
    window.attachEvent("onstorage", handle_storage);
}

function handle_storage(e)
{
    if (!e) {
        e = window.event;
    }
    // showStorage();
}

Session

Session 即会话, 指一种持续性的、双向的连接。Session 和 Cookie 本质上没什么区别, 都是针对 HTTP 协议局限性而提出的一种保持客户端和服务器之间保持会话状态的机制。

Session 指用户在浏览某个网站时, 从进入网站到浏览器关闭这段时间内的会话。

要使用 Session 必须在程序的最开始处执行 session_start(), 前面不能有任何输出内容, 否则就会抛出 WARNING 级别错误。

Session 通过一个称为 PHPSESSID 的 Cookie 和服务器联系。Session 是通过 SessionID 判断客户端用户的, 即 Session 文件的文件名。

Session 的回收是被动的, 为了保证过期的 Session 能被正常回收, 可以修改 PHP配置文件中的 session.gc_divisor 参数提高回收率(太大了会增加负载), 或者设置一个变量判断是否过期。

访问量大的网站可以通过使用 session_set_save_handler函数来将 session 存储在 Data Base(数据库、内存表、APC等)中。

上一篇 下一篇

猜你喜欢

热点阅读