成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP Socket 深度探索 (一)

myeveryheart / 1538人閱讀

摘要:首先,解釋一下目前領(lǐng)域比較易于混淆的概念有阻塞非阻塞同步異步多路復(fù)用等。在這些多路復(fù)用的模式中,異步阻塞非阻塞模式的擴(kuò)展性和性能最好。

簡介

Socket(套接字)一直是網(wǎng)絡(luò)層的底層核心內(nèi)容,也是 TCP/IP 以及 UDP 底層協(xié)議的實(shí)現(xiàn)通道。隨著互聯(lián)網(wǎng)信息時(shí)代的爆炸式發(fā)展,當(dāng)代服務(wù)器的性能問題面臨越來越大的挑戰(zhàn),著名的 C10K 問題(http://www.kegel.com/c10k.html)也隨之出現(xiàn)。幸虧通過大牛們的不懈努力,區(qū)別于傳統(tǒng)的 select/poll 的 epoll/kqueue 方式出現(xiàn)了,目前 linux2.6 以上的內(nèi)核都普遍支持,這是 Socket 領(lǐng)域一項(xiàng)巨大的進(jìn)步,不僅解決了 C10K 問題,也漸漸成為了當(dāng)代互聯(lián)網(wǎng)的底層核心技術(shù)。libevent 庫就是其中一個(gè)比較出彩的項(xiàng)目(現(xiàn)在非常多的開源項(xiàng)目都有用到,包括 Memcached),感興趣的朋友可以研究一下。

由于網(wǎng)絡(luò)上系統(tǒng)介紹這個(gè)部分的文章并不多,而涉及 PHP 的就更少了,所以石頭君在這里希望通過《Socket深度探究4PHP》這個(gè)系列給對這個(gè)領(lǐng)域感興趣的讀者們一定的幫助,也希望大家能和我一起對這個(gè)問題進(jìn)行更深入的探討。首先,解釋一下目前 Socket 領(lǐng)域比較易于混淆的概念有:阻塞/非阻塞、同步/異步、多路復(fù)用等。

閱讀準(zhǔn)備

1、阻塞/非阻塞:這兩個(gè)概念是針對 IO 過程中進(jìn)程的狀態(tài)來說的,阻塞 IO 是指調(diào)用結(jié)果返回之前,當(dāng)前線程會被掛起;相反,非阻塞指在不能立刻得到結(jié)果之前,該函數(shù)不會阻塞當(dāng)前線程,而會立刻返回。

2、同步/異步:這兩個(gè)概念是針對調(diào)用如果返回結(jié)果來說的,所謂同步,就是在發(fā)出一個(gè)功能調(diào)用時(shí),在沒有得到結(jié)果之前,該調(diào)用就不返回;相反,當(dāng)一個(gè)異步過程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結(jié)果,實(shí)際處理這個(gè)調(diào)用的部件在完成后,通過狀態(tài)、通知和回調(diào)來通知調(diào)用者。

3、多路復(fù)用(IO/Multiplexing):為了提高數(shù)據(jù)信息在網(wǎng)絡(luò)通信線路中傳輸?shù)男剩谝粭l物理通信線路上建立多條邏輯通信信道,同時(shí)傳輸若干路信號的技術(shù)就叫做多路復(fù)用技術(shù)。對于 Socket 來說,應(yīng)該說能同時(shí)處理多個(gè)連接的模型都應(yīng)該被稱為多路復(fù)用,目前比較常用的有 select/poll/epoll/kqueue 這些 IO 模型(目前也有像 Apache 這種每個(gè)連接用多帶帶的進(jìn)程/線程來處理的 IO 模型,但是效率相對比較差,也很容易出問題,所以暫時(shí)不做介紹了)。在這些多路復(fù)用的模式中,異步阻塞/非阻塞模式的擴(kuò)展性和性能最好。

同步阻塞IO模型

socket_server.php

 
**/  
set_time_limit(0);  
class SocketServer   
{  
    private static $socket;  
    function SocketServer($port)   
    {  
        global $errno, $errstr;  
        if ($port < 1024) {  
            die("Port must be a number which bigger than 1024/n");  
        }  
          
        $socket = stream_socket_server("tcp://0.0.0.0:{$port}", $errno, $errstr);  
        if (!$socket) die("$errstr ($errno)");  
          
//      stream_set_timeout($socket, -1); // 保證服務(wù)端 socket 不會超時(shí),似乎沒用:)  
          
        while ($conn = stream_socket_accept($socket, -1)) { // 這樣設(shè)置不超時(shí)才油用  
            static $id = 0;  
            static $ct = 0;  
            $ct_last = $ct;  
            $ct_data = "";  
            $buffer = "";  
            $id++; // increase on each accept  
            echo "Client $id come./n";  
            while (!preg_match("http://r?/n/", $buffer)) { // 沒有讀到結(jié)束符,繼續(xù)讀  
//              if (feof($conn)) break; // 防止 popen 和 fread 的 bug 導(dǎo)致的死循環(huán)  
                $buffer = fread($conn, 1024);  
                echo "R"; // 打印讀的次數(shù)  
                $ct += strlen($buffer);  
                $ct_data .= preg_replace("http://r?/n/", "", $buffer);  
            }  
            $ct_size = ($ct - $ct_last) * 8;  
            echo "[$id] " . __METHOD__ . " > " . $ct_data . "/n";  
            fwrite($conn, "Received $ct_size byte data./r/n");  
            fclose($conn);  
        }  
          
        fclose($socket);  
    }  
}  
new SocketServer(2000);  

socket_client.php

 
**/  
function debug ($msg)  
{  
//  echo $msg;  
    error_log($msg, 3, "/tmp/socket.log");  
}  
if ($argv[1]) {  
      
    $socket_client = stream_socket_client("tcp://0.0.0.0:2000", $errno, $errstr, 30);  
      
//  stream_set_blocking($socket_client, 0);  
//  stream_set_timeout($socket_client, 0, 100000);  
      
    if (!$socket_client) {  
        die("$errstr ($errno)");  
    } else {  
        $msg = trim($argv[1]);  
        for ($i = 0; $i < 10; $i++) {  
            $res = fwrite($socket_client, "$msg($i)");  
            usleep(100000);  
            echo "W"; // 打印寫的次數(shù)  
//          debug(fread($socket_client, 1024)); // 將產(chǎn)生死鎖,因?yàn)?fread 在阻塞模式下未讀到數(shù)據(jù)時(shí)將等待  
        }  
        fwrite($socket_client, "/r/n"); // 傳輸結(jié)束符  
        debug(fread($socket_client, 1024));  
        fclose($socket_client);  
    }  
}  
else {  
      
//  $phArr = array();  
//  for ($i = 0; $i < 10; $i++) {  
//      $phArr[$i] = popen("php ".__FILE__." "{$i}:test"", "r");  
//  }  
//  foreach ($phArr as $ph) {  
//      pclose($ph);  
//  }  
      
    for ($i = 0; $i < 10; $i++) {  
        system("php ".__FILE__." "{$i}:test"");  
    }  
}  
代碼分析

首先,解釋一下以上的代碼邏輯:客戶端 socket_client.php 循環(huán)發(fā)送數(shù)據(jù),最后發(fā)送結(jié)束符;服務(wù)端 socket_server.php 使用 accept 阻塞方式接收 socket 連接,然后循環(huán)接收數(shù)據(jù),直到收到結(jié)束符,返回結(jié)果數(shù)據(jù)(接收到的字節(jié)數(shù))。雖然邏輯很簡單,但是其中有幾種情況很值得分析一下:

A> 默認(rèn)情況下,運(yùn)行 php socket_client.php test,客戶端打出 10 個(gè) W,服務(wù)端打出若干個(gè) R 后面是接收到的數(shù)據(jù),/tmp/socket.log 記錄下服務(wù)端返回的接收結(jié)果數(shù)據(jù)。這種情況很容易理解,不再贅述。然后,使用 telnet 命令同時(shí)打開多個(gè)客戶端,你會發(fā)現(xiàn)服務(wù)器一個(gè)時(shí)間只處理一個(gè)客戶端,其他需要在后面“排隊(duì)”;這就是阻塞 IO 的特點(diǎn),這種模式的弱點(diǎn)很明顯,效率極低。

B> 只打開 socket_client.php 第 26 行的注釋代碼,再次運(yùn)行 php socket_client.php test 客戶端打出一個(gè) W,服務(wù)端也打出一個(gè) R,之后兩個(gè)程序都卡住了。這是為什么呢,分析邏輯后你會發(fā)現(xiàn),這是由于客戶端在未發(fā)送結(jié)束符之前就向服務(wù)端要返回?cái)?shù)據(jù);而服務(wù)端由于未收到結(jié)束符,也在向客戶端要結(jié)束符,造成死鎖。而之所以只打出一個(gè) W 和 R,是因?yàn)?fread 默認(rèn)是阻塞的。要解決這個(gè)死鎖,必須打開 socket_client.php 第 16 行的注釋代碼,給 socket 設(shè)置一個(gè) 0.1 秒的超時(shí),再次運(yùn)行你會發(fā)現(xiàn)隔 0.1 秒出現(xiàn)一個(gè) W 和 R 之后正常結(jié)束,服務(wù)端返回的接收結(jié)果數(shù)據(jù)也正常記錄了??梢?fread 缺省是阻塞的,我們在編程的時(shí)候要特別注意,如果沒有設(shè)置超時(shí),就很容易會出現(xiàn)死鎖。

C> 只打開 15 行注釋,運(yùn)行 php socket_client.php test,結(jié)果基本和情況 A 相同,唯一不同的是 /tmp/socket.log 沒有記錄下返回?cái)?shù)據(jù)。這里可以看出客戶端運(yùn)行在阻塞和非阻塞模式的區(qū)別,當(dāng)然在客戶端不在乎接受結(jié)果的情況下,可以使用非阻塞模式來獲得最大效率。

D> 運(yùn)行 php socket_client.php 是連續(xù)運(yùn)行 10 次上面的邏輯,這個(gè)沒什么問題;但是很奇怪的是如果你使用 35 - 41 行的代碼,用 popen 同時(shí)開啟 10 個(gè)進(jìn)程來運(yùn)行,就會造成服務(wù)器端的死循環(huán),十分怪異!后來經(jīng)調(diào)查發(fā)現(xiàn)只要是用 popen 打開的進(jìn)程創(chuàng)建的連接會導(dǎo)致 fread 或者 socket_read 出錯(cuò)直接返回空字串,從而導(dǎo)致死循環(huán),查閱 PHP 源代碼后發(fā)現(xiàn) PHP 的 popen 和 fread 函數(shù)已經(jīng)完全不是 C 原生的了,里面都插入了大量的 php_stream_* 實(shí)現(xiàn)邏輯,初步估計(jì)是其中的某個(gè) bug 導(dǎo)致的 Socket 連接中斷所導(dǎo)致的,解決方法就是打開 socket_server.php 中 31 行的代碼,如果連接中斷則跳出循環(huán),但是這樣一來就會有很多數(shù)據(jù)丟失了,這個(gè)問題需要特別注意!

同步非阻塞IO模型

select_server.php

 
**/  
set_time_limit(0);  
class SelectSocketServer   
{  
    private static $socket;  
    private static $timeout = 60;  
    private static $maxconns = 1024;  
    private static $connections = array();  
    function SelectSocketServer($port)   
    {  
        global $errno, $errstr;  
        if ($port < 1024) {  
            die("Port must be a number which bigger than 1024/n");  
        }  
          
        $socket = socket_create_listen($port);  
        if (!$socket) die("Listen $port failed");  
          
        socket_set_nonblock($socket); // 非阻塞  
          
        while (true)   
        {  
            $readfds = array_merge(self::$connections, array($socket));  
            $writefds = array();  
              
            // 選擇一個(gè)連接,獲取讀、寫連接通道  
            if (socket_select($readfds, $writefds, $e = null, $t = self::$timeout))   
            {  
                // 如果是當(dāng)前服務(wù)端的監(jiān)聽連接  
                if (in_array($socket, $readfds)) {  
                    // 接受客戶端連接  
                    $newconn = socket_accept($socket);  
                    $i = (int) $newconn;  
                    $reject = "";  
                    if (count(self::$connections) >= self::$maxconns) {  
                        $reject = "Server full, Try again later./n";  
                    }  
                    // 將當(dāng)前客戶端連接放入 socket_select 選擇  
                    self::$connections[$i] = $newconn;  
                    // 輸入的連接資源緩存容器  
                    $writefds[$i] = $newconn;  
                    // 連接不正常  
                    if ($reject) {  
                        socket_write($writefds[$i], $reject);  
                        unset($writefds[$i]);  
                        self::close($i);  
                    } else {  
                        echo "Client $i come./n";  
                    }  
                    // remove the listening socket from the clients-with-data array  
                    $key = array_search($socket, $readfds);  
                    unset($readfds[$key]);  
                }  
                  
                // 輪循讀通道  
                foreach ($readfds as $rfd) {  
                    // 客戶端連接  
                    $i = (int) $rfd;  
                    // 從通道讀取  
                    $line = @socket_read($rfd, 2048, PHP_NORMAL_READ);  
                    if ($line === false) {  
                        // 讀取不到內(nèi)容,結(jié)束連接            
                        echo "Connection closed on socket $i./n";  
                        self::close($i);  
                        continue;  
                    }  
                    $tmp = substr($line, -1);  
                    if ($tmp != "/r" && $tmp != "/n") {  
                        // 等待更多數(shù)據(jù)  
                        continue;  
                    }  
                    // 處理邏輯  
                    $line = trim($line);  
                    if ($line == "quit") {  
                        echo "Client $i quit./n";  
                        self::close($i);  
                        break;  
                    }  
                    if ($line) {  
                        echo "Client $i >>" . $line . "/n";  
                    }  
                }  
                  
                // 輪循寫通道  
                foreach ($writefds as $wfd) {  
                    $i = (int) $wfd;  
                    $w = socket_write($wfd, "Welcome Client $i!/n");  
                }  
            }  
        }  
    }  
      
    function close ($i)   
    {  
        socket_shutdown(self::$connections[$i]);  
        socket_close(self::$connections[$i]);  
        unset(self::$connections[$i]);  
    }  
}  
new SelectSocketServer(2000);  

select_client.php

 
**/  
function debug ($msg)  
{  
//  echo $msg;  
    error_log($msg, 3, "/tmp/socket.log");  
}  
if ($argv[1]) {  
      
    $socket_client = stream_socket_client("tcp://0.0.0.0:2000", $errno, $errstr, 30);  
      
//  stream_set_timeout($socket_client, 0, 100000);  
      
    if (!$socket_client) {  
        die("$errstr ($errno)");  
    } else {  
        $msg = trim($argv[1]);  
        for ($i = 0; $i < 10; $i++) {  
            $res = fwrite($socket_client, "$msg($i)/n");  
            usleep(100000);  
//          debug(fread($socket_client, 1024)); // 將產(chǎn)生死鎖,因?yàn)?fread 在阻塞模式下未讀到數(shù)據(jù)時(shí)將等待  
        }  
        fwrite($socket_client, "quit/n"); // add end token  
        debug(fread($socket_client, 1024));  
        fclose($socket_client);  
    }  
}  
else {  
      
    $phArr = array();  
    for ($i = 0; $i < 10; $i++) {  
        $phArr[$i] = popen("php ".__FILE__." "{$i}:test"", "r");  
    }  
    foreach ($phArr as $ph) {  
        pclose($ph);  
    }  
      
//  for ($i = 0; $i < 10; $i++) {  
//      system("php ".__FILE__." "{$i}:test"");  
//  }  
}  
代碼分析

以上代碼的邏輯也很簡單,select_server.php 實(shí)現(xiàn)了一個(gè)類似聊天室的功能,你可以使用 telnet 工具登錄上去,和其他用戶文字聊天,也可以鍵入“quit”命令離開;而 select_client.php 則模擬了一個(gè)登錄用戶連續(xù)發(fā) 10 條信息,然后退出。這里也分析兩個(gè)問題:

A> 這里如果我們執(zhí)行 php select_client.php 程序?qū)瑫r(shí)打開 10 個(gè)連接,同時(shí)進(jìn)行模擬登錄用戶操作;觀察服務(wù)端打印的數(shù)據(jù)你會發(fā)現(xiàn)服務(wù)端確實(shí)是在同時(shí)處理這些連接,這就是多路復(fù)用實(shí)現(xiàn)的非阻塞 IO 模型,當(dāng)然這個(gè)模型并沒有真正的實(shí)現(xiàn)異步,因?yàn)樽罱K服務(wù)端程序還是要去通道里面讀取數(shù)據(jù),得到結(jié)果后同步返回給客戶端。如果這次你也使用 telnet 命令同時(shí)打開多個(gè)客戶端,你會發(fā)現(xiàn)服務(wù)端可以同時(shí)處理這些連接,這就是非阻塞 IO,當(dāng)然比古老的阻塞 IO 效率要高多了,但是這種模式還是有局限的,繼續(xù)看下去你就會發(fā)現(xiàn)了~

B> 我在 select_server.php 中設(shè)置了幾個(gè)參數(shù),大家可以調(diào)整試試:
$timeout :表示的是 select 的超時(shí)時(shí)間,這個(gè)一般來說不要太短,否則會導(dǎo)致 CPU 負(fù)載過高。
$maxconns :表示的是最大連接數(shù),客戶端超過這個(gè)數(shù)的話,服務(wù)器會拒絕接收。這里要提到的一點(diǎn)是,由于 select 是通過句柄來讀寫的,所以會受到系統(tǒng)默認(rèn)參數(shù) __FD_SETSIZE 的限制,一般默認(rèn)值為 1024,修改的話需要重新編譯內(nèi)核;另外通過測試發(fā)現(xiàn) select 模式的性能會隨著連接數(shù)的增大而線性便差(詳情見《Socket深度探究4PHP(二)》),這也就是 select 模式最大的問題所在,所以如果是超高并發(fā)服務(wù)器建議使用下一種模式。

異步非阻塞IO模型

epoll_server.php

 
 *  
 * Defined constants: 
 *  
 * EV_TIMEOUT (integer) 
 * EV_READ (integer) 
 * EV_WRITE (integer) 
 * EV_SIGNAL (integer) 
 * EV_PERSIST (integer) 
 * EVLOOP_NONBLOCK (integer) 
 * EVLOOP_ONCE (integer) 
**/  
set_time_limit(0);  
class EpollSocketServer  
{  
    private static $socket;  
    private static $connections;  
    private static $buffers;  
      
    function EpollSocketServer ($port)  
    {  
        global $errno, $errstr;  
          
        if (!extension_loaded("libevent")) {  
            die("Please install libevent extension firstly/n");  
        }  
          
        if ($port < 1024) {  
            die("Port must be a number which bigger than 1024/n");  
        }  
          
        $socket_server = stream_socket_server("tcp://0.0.0.0:{$port}", $errno, $errstr);  
        if (!$socket_server) die("$errstr ($errno)");  
          
        stream_set_blocking($socket_server, 0); // 非阻塞  
          
        $base = event_base_new();  
        $event = event_new();  
        event_set($event, $socket_server, EV_READ | EV_PERSIST, array(__CLASS__, "ev_accept"), $base);  
        event_base_set($event, $base);  
        event_add($event);  
        event_base_loop($base);  
          
        self::$connections = array();  
        self::$buffers = array();  
    }  
      
    function ev_accept($socket, $flag, $base)   
    {  
        static $id = 0;  
      
        $connection = stream_socket_accept($socket);  
        stream_set_blocking($connection, 0);  
      
        $id++; // increase on each accept  
      
        $buffer = event_buffer_new($connection, array(__CLASS__, "ev_read"), array(__CLASS__, "ev_write"), array(__CLASS__, "ev_error"), $id);  
        event_buffer_base_set($buffer, $base);  
        event_buffer_timeout_set($buffer, 30, 30);  
        event_buffer_watermark_set($buffer, EV_READ, 0, 0xffffff);  
        event_buffer_priority_set($buffer, 10);  
        event_buffer_enable($buffer, EV_READ | EV_PERSIST);  
      
        // we need to save both buffer and connection outside  
        self::$connections[$id] = $connection;  
        self::$buffers[$id] = $buffer;  
    }  
      
    function ev_error($buffer, $error, $id)   
    {  
        event_buffer_disable(self::$buffers[$id], EV_READ | EV_WRITE);  
        event_buffer_free(self::$buffers[$id]);  
        fclose(self::$connections[$id]);  
        unset(self::$buffers[$id], self::$connections[$id]);  
    }  
      
    function ev_read($buffer, $id)   
    {  
        static $ct = 0;  
        $ct_last = $ct;  
        $ct_data = "";  
        while ($read = event_buffer_read($buffer, 1024)) {  
            $ct += strlen($read);  
            $ct_data .= $read;  
        }  
        $ct_size = ($ct - $ct_last) * 8;  
        echo "[$id] " . __METHOD__ . " > " . $ct_data . "/n";  
        event_buffer_write($buffer, "Received $ct_size byte data./r/n");  
    }  
      
    function ev_write($buffer, $id)   
    {  
        echo "[$id] " . __METHOD__ . "/n";  
    }  
}  
new EpollSocketServer(2000);  

epoll_client.php

 
**/  
function debug ($msg)  
{  
//  echo $msg;  
    error_log($msg, 3, "/tmp/socket.log");  
}  
if ($argv[1]) {  
    $socket_client = stream_socket_client("tcp://0.0.0.0:2000", $errno, $errstr, 30);  
//  stream_set_blocking($socket_client, 0);  
    if (!$socket_client) {  
        die("$errstr ($errno)");  
    } else {  
        $msg = trim($argv[1]);  
        for ($i = 0; $i < 10; $i++) {  
            $res = fwrite($socket_client, "$msg($i)");  
            usleep(100000);  
            debug(fread($socket_client, 1024));  
        }  
        fclose($socket_client);  
    }  
}  
else {  
      
    $phArr = array();  
    for ($i = 0; $i < 10; $i++) {  
        $phArr[$i] = popen("php ".__FILE__." "{$i}:test"", "r");  
    }  
    foreach ($phArr as $ph) {  
        pclose($ph);  
    }  
      
//  for ($i = 0; $i < 10; $i++) {  
//      system("php ".__FILE__." "{$i}:test"");  
//  }  
}  
代碼解析

先說一下,以上的例子是基于 PHP 的 libevent 擴(kuò)展實(shí)現(xiàn)的,需要運(yùn)行的話要先安裝此擴(kuò)展,參考:http://pecl.php.net/package/l...。

這個(gè)例子做的事情和前面介紹的第一個(gè)模型一樣,epoll_server.php 實(shí)現(xiàn)的服務(wù)端也是接受客戶端數(shù)據(jù),然后返回結(jié)果(接收到的字節(jié)數(shù))。但是,當(dāng)你運(yùn)行 php epoll_client.php 的時(shí)候你會發(fā)現(xiàn)服務(wù)端打印出來的結(jié)果和 accept 阻塞模型就大不一樣了,當(dāng)然運(yùn)行效率也有極大的提升,這是為什么呢?接下來就介紹一下 epoll/kqueue 模型:在介紹 select 模式的時(shí)候我們提到了這種模式的局限,而 epoll 就是為了解決 poll 的這兩個(gè)缺陷而生的。首先,epoll 模式基本沒有限制(參考 cat /proc/sys/fs/file-max 默認(rèn)就達(dá)到 300K,很令人興奮吧,其實(shí)這也就是所謂基于 epoll 的 Erlang 服務(wù)端可以同時(shí)處理這么多并發(fā)連接的根本原因,不過現(xiàn)在 PHP 理論上也可以做到了,呵呵);另外,epoll 模式的性能也不會像 select 模式那樣隨著連接數(shù)的增大而變差,測試發(fā)現(xiàn)性能還是很穩(wěn)定的(下篇會有詳細(xì)介紹)。

epoll 工作有兩種模式 LT(level triggered) 和 ET(edge-triggered),前者是缺省模式,同時(shí)支持阻塞和非阻塞 IO 模式,雖然性能比后者差點(diǎn),但是比較穩(wěn)定,一般來說在實(shí)際運(yùn)用中,我們都是用這種模式(ET 模式和 WinSock 都是純異步非阻塞模型)。而另外一點(diǎn)要說的是 libevent 是在編譯階段選擇系統(tǒng)的 I/O demultiplex 機(jī)制的,不支持在運(yùn)行階段根據(jù)配置再次選擇,所以我們在這里也就不細(xì)討論 libevent 的實(shí)現(xiàn)的細(xì)節(jié)了,如果朋友有興趣進(jìn)一步了解的話,請參考:http://monkey.org/~provos/lib...。

到這里,第一部分的內(nèi)容結(jié)束了,相信大家已經(jīng)了解了 Socket 編程的幾個(gè)重點(diǎn)概念和一些實(shí)戰(zhàn)技巧,在下一篇《Socket深度探究4PHP(二) 》我將會對 select/poll/epoll/kqueue 幾種模式做一下深入的介紹和對比,另外也會涉及到兩種重要的 I/O 多路復(fù)用模式:Reactor 和 Proactor 模式。

To be continued ...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/26091.html

相關(guān)文章

  • cnn卷積神經(jīng)網(wǎng)絡(luò)打造人臉登錄系統(tǒng)

    摘要:本文基于環(huán)境,采用為基礎(chǔ)來構(gòu)建實(shí)時(shí)人臉檢測與識別系統(tǒng),探索人臉識別系統(tǒng)在現(xiàn)實(shí)應(yīng)用中的難點(diǎn)。對于人臉檢測方法,效果好于的方法,但是檢測力度也難以達(dá)到現(xiàn)場應(yīng)用標(biāo)準(zhǔn)。本文中,我們采用了基于深度學(xué)習(xí)方法的人臉檢測系統(tǒng)。 git地址:https://github.com/chenlinzho... 本文主要介紹了系統(tǒng)涉及的人臉檢測與識別的詳細(xì)方法,該系統(tǒng)基于python2.7.10/opencv...

    jackwang 評論0 收藏0
  • cnn卷積神經(jīng)網(wǎng)絡(luò)打造人臉登錄系統(tǒng)

    摘要:本文基于環(huán)境,采用為基礎(chǔ)來構(gòu)建實(shí)時(shí)人臉檢測與識別系統(tǒng),探索人臉識別系統(tǒng)在現(xiàn)實(shí)應(yīng)用中的難點(diǎn)。對于人臉檢測方法,效果好于的方法,但是檢測力度也難以達(dá)到現(xiàn)場應(yīng)用標(biāo)準(zhǔn)。本文中,我們采用了基于深度學(xué)習(xí)方法的人臉檢測系統(tǒng)。 git地址:https://github.com/chenlinzho... 本文主要介紹了系統(tǒng)涉及的人臉檢測與識別的詳細(xì)方法,該系統(tǒng)基于python2.7.10/opencv...

    KavenFan 評論0 收藏0
  • 利用遺傳算法優(yōu)化神經(jīng)網(wǎng)絡(luò):Uber提出深度學(xué)習(xí)訓(xùn)練新方式

    摘要:和的得分均未超過右遺傳算法在也表現(xiàn)得很好。深度遺傳算法成功演化了有著萬自由參數(shù)的網(wǎng)絡(luò),這是通過一個(gè)傳統(tǒng)的進(jìn)化算法演化的較大的神經(jīng)網(wǎng)絡(luò)。 Uber 涉及領(lǐng)域廣泛,其中許多領(lǐng)域都可以利用機(jī)器學(xué)習(xí)改進(jìn)其運(yùn)作。開發(fā)包括神經(jīng)進(jìn)化在內(nèi)的各種有力的學(xué)習(xí)方法將幫助 Uber 發(fā)展更安全、更可靠的運(yùn)輸方案。遺傳算法——訓(xùn)練深度學(xué)習(xí)網(wǎng)絡(luò)的有力競爭者我們驚訝地發(fā)現(xiàn),通過使用我們發(fā)明的一種新技術(shù)來高效演化 DNN,...

    AlienZHOU 評論0 收藏0
  • JavaScript是如何工作: 深入探索 websocket 和HTTP/2與SSE +如何選擇正

    摘要:數(shù)據(jù)作為消息通過傳輸,每個(gè)消息由一個(gè)或多個(gè)幀組成,其中包含正在發(fā)送的數(shù)據(jù)有效負(fù)載。幀數(shù)據(jù)如上所述,數(shù)據(jù)可以被分割成多個(gè)幀。但是,規(guī)范希望能夠處理交錯(cuò)的控制幀。 文章底部分享給大家一套 react + socket 實(shí)戰(zhàn)教程 這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第5篇。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過了前面的章...

    cuieney 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<