## Socket 操作

### TCP/IP 是什么?
* TCP/IP 是個協議組,分為三個層次:網絡層、傳輸層和應用層。
* 在網絡層有 IP 、ICMP 和 IGMP 協議。
* 在傳輸層中有 TCP 和 UDP 協議。
* 在應用層有FTP、HTTP、TELNET、SMTP、DNS 等協議。
### Socket 是什么?
Socket 是應用層與 TCP/IP 協議族通信的中間軟件抽象層,一組接口,把復雜的 TCP/IP 協議族隱藏在 Socket 接口后面。
### Socket 原理
Socket 連接至少需要一對套接字,分為 clientSocket 和 serverSocket。
Socket連接分為3個步驟:
* 服務器監聽:服務器并不定位具體客戶端的套接字,而是時刻處于監聽狀態。
* 客戶端請求:客戶端的套接字要描述它要連接的服務器的套接字,提供地址和端口號,然后向服務器套接字提出連接請求。
* 連接確認:當服務器套接字收到客戶端套接字發來的請求后,就響應客戶端套接字的請求,把服務器端的套接字的描述發給客戶端。一旦客戶端確認了此描述,就正式建立連接。而服務器套接字繼續處于監聽狀態,繼續接收其他客戶端套接字的連接請求。
長鏈接和短鏈接:
* 短鏈接: 短連接是指 SOCKET 連接后,發送完數據后,馬上斷開連接。
* 長鏈接: 長連接是指 SOCKET 連接后,不管是否使用,繼續保持鏈接。
參考鏈接:[TCP/IP 和 Socket](http://blog.chinaunix.net/uid-9622484-id-3392992.html)
### Socket 發送 HTTP 請求
```
<?php
class HttpClient
{
const SEP = "\r\n"; // 分隔符
const VERSION = 'HTTP/1.1'; // 協議的版本
private $line = ''; // 請求行
private $body = ''; // 請求正文
private $headers = []; // 請求頭
private $uInfo = []; // url信息
public function __construct($url = null)
{
if ($url) {
$this->setUrl($url);
}
}
/**
* 設置并解析URL
* @param string $url
*/
public function setUrl($url)
{
$uInfo = parse_url($url);
if (!isset($uInfo['port'])) {
$uInfo['port'] = 80;
}
if (!isset($uInfo['path'])) {
$uInfo['path'] = '/';
}
$this->uInfo = $uInfo;
}
/**
* 添加請求頭信息
* @param string $header
*/
public function setHeader($header)
{
$this->headers[] = $header;
}
/**
* GET 請求
* @return array
*/
public function get()
{
$this->setLine('GET');
return $this->request();
}
/**
* POST 請求
* @param array
* @return array
*/
public function post($data = [])
{
$this->setLine('POST');
$this->setBody($data);
$this->setHeader('Content-Type: application/x-www-form-urlencoded');
$this->setHeader('Content-Length: ' . strlen($this->body));
return $this->request();
}
/**
* 構造請求行信息
* @param string $line GET|POST
*/
private function setLine($line)
{
$this->line .= ($line . ' ' . $this->uInfo['path']);
if (isset($this->uInfo['query'])) {
$this->line .= ('?' . $this->uInfo['query']);
}
$this->line .= (' ' . self::VERSION);
}
/**
* 構造消息正文
* @param array $data
*/
private function setBody($data)
{
if ($data) {
$this->body = http_build_query($data);
}
}
/**
* 發送數據
* @return array
*/
private function request()
{
$this->setHeader('Host: ' . $this->uInfo['host']);
$this->setHeader('Connection: close');
$this->setHeader('User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0');
$handle = fsockopen($this->uInfo['host'], $this->uInfo['port']);
$str = $this->line . self::SEP;
$str .= implode(self::SEP, $this->headers);
$str .= self::SEP . self::SEP;
if (!empty($this->body)) {
$str .= $this->body;
}
fwrite($handle, $str);
$response = '';
while (!feof($handle)) {
$response .= fgets($handle);
}
fclose($handle);
$this->response = $response;
list($headers, $content) = explode(self::SEP . self::SEP, $response);
return [
'headers' => $headers,
'content' => $content,
];
}
}
$http = new HttpClient('http://forum-api.local/test');
/* ------------- 發送 GET 請求 ------------ */
$response = $http->get();
var_dump($response['headers']);
var_dump($response['content']);
exit();
/* ------------- 發送 POST 請求 ------------ */
$data = [
'name' => 'kate green',
'age' => 12,
];
$response = $http->post($data);
var_dump($response['headers']);
var_dump($response['content']);
?>
```
- 基本語法
- PHP標記
- 指令分隔符
- 從HTML中分離
- 注釋
- 數據類型
- 布爾值
- 整數
- 浮點數
- 字符串
- 數組
- 對象
- 資源
- 空值
- 變量
- 基礎
- 預定義變量
- 變量范圍
- 可變變量
- 常量
- 常量語法
- 魔術常量
- 運算符
- 算術運算符
- 賦值運算符
- 位運算符
- 比較運算符
- 遞增與遞減運算符
- 邏輯運算符
- 字符串運算符
- 數組運算符
- 類型運算符
- 流程控制
- if條件結構
- switch條件結構
- while循環結構
- do-while循環結構
- for循環結構
- foreach循環結構
- 包含文件
- 函數
- 自定義函數
- 可變函數
- 匿名函數
- 遞歸函數
- 類與對象
- 基本概念
- 屬性
- 方法
- 類常量
- 構造函數和析構函數
- 訪問控制
- 繼承
- 抽象類
- 接口
- Trait
- 重載
- 對象遍歷
- 魔術方法
- Final關鍵字
- 命名空間
- 自動加載
- 錯誤處理
- 錯誤顯示
- 錯誤日志
- 錯誤報告
- 自定義錯誤處理
- 異常處理
- 異常處理機制
- 擴展異常處理類
- 字符操作
- 數組操作
- 時間操作
- 表單操作
- GET提交
- POST提交
- 文件上傳
- 會話控制
- COOKIE操作
- SESSION操作
- 文件操作
- 文件屬性
- 讀取文件
- 寫入文件
- 文件管理
- 文件鎖
- 目錄處理
- 路徑處理
- 網絡操作
- HTTP協議
- Socket操作
- CURL操作
- PDO操作
- 介紹
- 連接管理
- 預處理語句
- 事務處理
- 錯誤處理
- 圖像操作
- 正則表達式
- 標準推薦
- 包管理器
- 設計模式
- 常用算法
- 安全防御
- XSS防御
- CSRF防御