如下內容轉自:https://www.cnblogs.com/loveyoume/p/6076101.html 和 https://www.cnblogs.com/WuNaiHuaLuo/p/6107771.htmlphp
什麼是TCP/IP、UDP?html
TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,是一個工業標準的協議集,它是爲廣域網(WANs)設計的。
UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種。
這裏有一張圖,代表了這些協議的關係。
編程
TCP/IP協議族包括運輸層、網絡層、鏈路層。如今你知道TCP/IP與UDP的關係了吧。
Socket在哪裏呢?
在圖1中,咱們沒有看到Socket的影子,那麼它到底在哪裏呢?仍是用圖來講話,一目瞭然。設計模式
原來Socket在這裏。
Socket是什麼呢?
Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。
你會使用它們嗎?
前人已經給咱們作了好多的事了,網絡間的通訊也就簡單了許多,但畢竟仍是有挺多工做要作的。之前聽到Socket編程,以爲它是比較高深的編程知識,可是隻要弄清Socket編程的工做原理,神祕的面紗也就揭開了。
一個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就創建起了鏈接,就能夠講話了。等交流結束,掛斷電話結束這次交談。 生活中的場景就解釋了這工做原理,也許TCP/IP協議族就是誕生於生活中,這也不必定。數組
先從服務器端提及。服務器端先初始化Socket,而後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端鏈接。在這時若是有個客戶端初始化一個Socket,而後鏈接服務器(connect),若是鏈接成功,這時客戶端與服務器端的鏈接就創建了。客戶端發送數據請求,服務器端接收請求並處理請求,而後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉鏈接,一次交互結束。緩存
socket相關函數:
----------------------------------------------------------------------------------------------
socket_accept() 接受一個Socket鏈接
socket_bind() 把socket綁定在一個IP地址和端口上
socket_clear_error() 清除socket的錯誤或者最後的錯誤代碼
socket_close() 關閉一個socket資源
socket_connect() 開始一個socket鏈接
socket_create_listen() 在指定端口打開一個socket監聽
socket_create_pair() 產生一對沒有區別的socket到一個數組裏
socket_create() 產生一個socket,至關於產生一個socket的數據結構
socket_get_option() 獲取socket選項
socket_getpeername() 獲取遠程相似主機的ip地址
socket_getsockname() 獲取本地socket的ip地址
socket_iovec_add() 添加一個新的向量到一個分散/聚合的數組
socket_iovec_alloc() 這個函數建立一個可以發送接收讀寫的iovec數據結構
socket_iovec_delete() 刪除一個已經分配的iovec
socket_iovec_fetch() 返回指定的iovec資源的數據
socket_iovec_free() 釋放一個iovec資源
socket_iovec_set() 設置iovec的數據新值
socket_last_error() 獲取當前socket的最後錯誤代碼
socket_listen() 監聽由指定socket的全部鏈接
socket_read() 讀取指定長度的數據
socket_readv() 讀取從分散/聚合數組過來的數據
socket_recv() 從socket裏結束數據到緩存
socket_recvfrom() 接受數據從指定的socket,若是沒有指定則默認當前socket
socket_recvmsg() 從iovec裏接受消息
socket_select() 多路選擇
socket_send() 這個函數發送數據到已鏈接的socket
socket_sendmsg() 發送消息到socket
socket_sendto() 發送消息到指定地址的socket
socket_set_block() 在socket裏設置爲塊模式
socket_set_nonblock() socket裏設置爲非塊模式
socket_set_option() 設置socket選項
socket_shutdown() 這個函數容許你關閉讀、寫、或者指定的socket
socket_strerror() 返回指定錯誤號的詳細錯誤
socket_write() 寫數據到socket緩存
socket_writev() 寫數據到分散/聚合數組服務器
其中 8 個經常使用的函數原型及簡單解釋網絡
socket的關鍵函數1:數據結構
socket_create($net參數1,$stream參數2,$protocol參數3)socket
做用:建立一個socket套接字,說白了,就是一個網絡數據流。
返回值:一個套接字,或者是false,參數錯誤發出E_WARNING警告
php的在線手冊那裏說得更清楚:
socket_create建立並返回一個套接字,也稱做一個通信節點。一個典型的網絡鏈接由 2 個套接字構成,一個運行在客戶端,另外一個運行在服務器端。
上面一句話是從php在線手冊那裏複製過來的。看到沒有,這裏說得意思是否是和我上面反反覆覆提到的客戶端與服務端如出一轍?呵呵。
參數1是:網絡協議,
網絡協議有哪些?它的選擇項就下面這三個:
AF_INET: IPv4 網絡協議。TCP 和 UDP 均可使用此協議。通常都用這個,你懂的。
AF_INET6: IPv6 網絡協議。TCP 和 UDP 均可使用此協議。
AF_UNIX: 本地通信協議。具備高性能和低成本的 IPC(進程間通信)。
參數2:套接字流,選項有:
SOCK_STREAM SOCK_DGRAM SOCK_SEQPACKET SOCK_RAW SOCK_RDM。
這裏只對前兩個進行解釋:
SOCK_STREAM TCP 協議套接字。
SOCK_DGRAM UDP協議套接字。
欲瞭解更多請連接這裏:http://php.net/manual/zh/function.socket-create.php
參數3:protocol協議,選項有:
SOL_TCP: TCP 協議。
SOL_UDP: UDP協議。
從這裏能夠看出,其實socket_create函數的第二個參數和第三個參數是相關聯的。
好比,假如你第一個參數應用IPv4協議:AF_INET,而後,第二個參數應用的是TCP套接字:SOCK_STREAM,
那麼第三個參數必需要用SOL_TCP,這個應該不難理解。
TCP 協議套接字嘛,固然只能用TCP協議了,是否是?若是你應用UDP套接字,那麼第三個參數該怎麼選擇我就不說了,呵呵,你懂的。
關鍵函數2:
socket_connect($socket參數1,$ip參數2,$port參數3)
做用:鏈接一個套接字,返回值爲true或者false
參數1:socket_create的函數返回值
參數2:ip地址
參數3:端口號
關鍵函數3:
socket_bind($socket參數1,$ip參數2,$port參數3)
做用:綁定一個套接字,返回值爲true或者false
參數1:socket_create的函數返回值
參數2:ip地址
參數3:端口號
關鍵函數4:
socket_listen($socket參數1,$backlog 參數2)
做用:監聽一個套接字,返回值爲true或者false
參數1:socket_create的函數返回值
參數2:最大監聽套接字個數
關鍵函數5:
socket_accept($socket)
做用:接收套接字的資源信息,成功返回套接字的信息資源,失敗爲false
參數:socket_create的函數返回值
關鍵函數6:
socket_read($socket參數1,$length參數2)
做用:讀取套接字的資源信息,
返回值:成功把套接字的資源轉化爲字符串信息,失敗爲false
參數1:socket_create或者socket_accept的函數返回值
參數2:讀取的字符串的長度
關鍵函數7:
socket_write($socket參數1,$msg參數2,$strlen參數3)
做用:把數據寫入套接字中
返回值:成功返回字符串的字節長度,失敗爲false
參數1:socket_create或者socket_accept的函數返回值
參數2:字符串
參數3:字符串的長度
關鍵函數8:
socket_close($socket)
做用:關閉套接字
返回值:成功返回true,失敗爲false
參數:socket_create或者socket_accept的函數返回值
這八個函數是socket的核心函數,下面列舉兩個個比較重要的函數
socket_last_error($socket),參數爲socket_create的返回值,做用是獲取套接字的最後一條錯誤碼號,返回值套接字code
socket_strerror($code),參數爲socket_last_error函數的返回值,獲取code的字符串信息,返回值也就是套接字的錯誤信息
socket_sever.php
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: yuanxiaolong01 5 * Date: 2018/10/4 6 * Time: 16:04 7 */ 8 9 $ip = "127.0.0.1"; 10 $ip = "0.0.0.0"; 11 $port = 8088; 12 13 if(($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {//建立一個套接字對象 14 echo "socket_create failed!!! msg:" . socket_strerror($socket) . "\n"; 15 } 16 17 if(socket_bind($socket, $ip, $port) == false) {//綁定須要監聽的ip和端口 18 echo "socket_bind failed!!! msg:" . socket_strerror(socket_last_error()) . "\n"; 19 } 20 21 if(socket_listen($socket, 4) == false) {//監聽套接流 22 echo "socket_listen failed!!! msg:" . socket_strerror(socket_last_error()) . "\n"; 23 } 24 25 do { 26 $accept_msg = socket_accept($socket);//接收綁定主機發過來的套接字流 27 28 if($accept_msg != false) { 29 //讀取套接流並轉換爲字符串 30 $read_msg = socket_read($accept_msg, 1024);//1024爲讀取字符串的長度 31 32 if($read_msg != false) { 33 socket_getpeername($accept_msg, $client_ip, $client_port); 34 echo "hava accept messege from " . $client_ip . " " . $client_port . ": " . $read_msg . "\n"; 35 36 $request = "server has accept messege\n"; 37 38 socket_write($accept_msg, $request, strlen($request)); 39 40 } else { 41 echo "socket_read() failed!!! msg:" . socket_strerror($read_msg) . "\n"; 42 } 43 } else { 44 echo "socket_accept() failed!!! msg:" . socket_strerror($accept_msg) . "\n"; 45 } 46 47 }while(true); 48 49 socket_close($socket); 50 echo "socket has been close!!\n";
socket_client.php
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: yuanxiaolong01 5 * Date: 2018/10/4 6 * Time: 16:53 7 */ 8 9 $ip = "127.0.0.1"; 10 $port = 8088; 11 12 if(($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {//建立一個套接字對象 13 echo "socket_create failed!!! msg:" . socket_strerror($socket) . "\n"; 14 } 15 16 //接收套接流的最大超時時間1秒,後面是微秒單位超時時間,設置爲零,表示無論它 17 socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 1, "usec" => 0)); 18 //發送套接流的最大超時時間爲6秒 19 socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 6, "usec" => 0)); 20 21 if(socket_connect($socket, $ip, $port) != false) { 22 $message = "l love you!"; 23 //轉爲GBK編碼,處理亂碼問題,這要看你的編碼狀況而定,每一個人的編碼都不一樣 24 // $message = mb_convert_encoding($message,'GBK','UTF-8'); 25 //向服務端寫入字符串信息 26 27 $i = 10; 28 29 while(--$i) { 30 $message = $message . $i; 31 if(socket_write($socket, $message, strlen($message)) == false){ 32 echo "fail to write!!! msg:" . socket_strerror(socket_last_error()); 33 }else{ 34 echo "client write success" . PHP_EOL; 35 //讀取服務端返回來的套接流信息 36 while($callback = socket_read($socket, 1024)){ 37 echo 'server return message is: ' . $callback . "\n"; 38 } 39 } 40 } 41 } else { 42 echo "connect failed!!! msg:" . socket_strerror(socket_last_error()); 43 } 44 45 socket_close($socket);