<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    一、我們可以且應(yīng)該優(yōu)化什么? 
      硬件
      
      操作系統(tǒng)/軟件庫(kù)
      
      SQL服務(wù)器(設(shè)置和查詢)
      
      應(yīng)用編程接口(API)
      
      應(yīng)用程序
      
      二、優(yōu)化硬件 
      如果你需要龐大的數(shù)據(jù)庫(kù)表(>2G),你應(yīng)該考慮使用64位的硬件結(jié)構(gòu),像Alpha、Sparc或即將推出的IA64。因?yàn)镸ySQL內(nèi)部使用大量64位的整數(shù),64位的CPU將提供更好的性能。
      
      對(duì)大數(shù)據(jù)庫(kù),優(yōu)化的次序一般是RAM、快速硬盤、CPU能力。
      
      更多的內(nèi)存通過將最常用的鍵碼頁(yè)面存放在內(nèi)存中可以加速鍵碼的更新。
      
      如果不使用事務(wù)安全(transaction-safe)的表或有大表并且想避免長(zhǎng)文件檢查,一臺(tái)UPS就能夠在電源故障時(shí)讓系統(tǒng)安全關(guān)閉。
      
      對(duì)于數(shù)據(jù)庫(kù)存放在一個(gè)專用服務(wù)器的系統(tǒng),應(yīng)該考慮1G的以太網(wǎng)。延遲與吞吐量同樣重要。
      
      三、優(yōu)化磁盤 
      為系統(tǒng)、程序和臨時(shí)文件配備一個(gè)專用磁盤,如果確是進(jìn)行很多修改工作,將更新日志和事務(wù)日志放在專用磁盤上。
      低尋道時(shí)間對(duì)數(shù)據(jù)庫(kù)磁盤非常重要。對(duì)與大表,你可以估計(jì)你將需要log(行數(shù))/log(索引塊長(zhǎng)度/3*2/(鍵碼長(zhǎng)度 + 數(shù)據(jù)指針長(zhǎng)度))+1次尋到才能找到一行。對(duì)于有500000行的表,索引Mediun int類型的列,需要log(500000) / log(1024/3*2/(3 + 2))+1=4次尋道。上述索引需要500000*7*3/2=5.2M的空間。實(shí)際上,大多數(shù)塊將被緩存,所以大概只需要1-2次尋道。
      然而對(duì)于寫入(如上),你將需要4次尋道請(qǐng)求來(lái)找到在哪里存放新鍵碼,而且一般要2次尋道來(lái)更新索引并寫入一行。
      
      對(duì)于非常大的數(shù)據(jù)庫(kù),你的應(yīng)用將受到磁盤尋道速度的限制,隨著數(shù)據(jù)量的增加呈N log N數(shù)據(jù)級(jí)遞增。
      
      將數(shù)據(jù)庫(kù)和表分在不同的磁盤上。在MySQL中,你可以為此而使用符號(hào)鏈接。
      條列磁盤(RAID 0)將提高讀和寫的吞吐量。
      帶鏡像的條列(RAID 0+1)將更安全并提高讀取的吞吐量。寫入的吞吐量將有所降低。
      不要對(duì)臨時(shí)文件或可以很容易地重建的數(shù)據(jù)所在的磁盤使用鏡像或RAID(除了RAID 0)。
      在Linux上,在引導(dǎo)時(shí)對(duì)磁盤使用命令hdparm -m16 -d1以啟用同時(shí)讀寫多個(gè)扇區(qū)和DMA功能。這可以將響應(yīng)時(shí)間提高5~50%。
      在Linux上,用async (默認(rèn))和noatime掛載磁盤(mount)。
      對(duì)于某些特定應(yīng)用,可以對(duì)某些特定表使用內(nèi)存磁盤,但通常不需要。
      
      四、優(yōu)化操作系統(tǒng) 
      不要交換區(qū)。如果內(nèi)存不足,增加更多的內(nèi)存或配置你的系統(tǒng)使用較少內(nèi)存。
      不要使用NFS磁盤(會(huì)有NFS鎖定的問題)。
      增加系統(tǒng)和MySQL服務(wù)器的打開文件數(shù)量。(在safe_mysqld腳本中加入ulimit -n #)。
      增加系統(tǒng)的進(jìn)程和線程數(shù)量。
      如果你有相對(duì)較少的大表,告訴文件系統(tǒng)不要將文件打碎在不同的磁道上(Solaris)。
      使用支持大文件的文件系統(tǒng)(Solaris)。
      選擇使用哪種文件系統(tǒng)。在Linux上的Reiserfs對(duì)于打開、讀寫都非常快。文件檢查只需幾秒種。
      
      五、操作系統(tǒng)移植
      PERL
      可在不同的操作系統(tǒng)和數(shù)據(jù)庫(kù)之間移植。
      適宜快速原型。
      應(yīng)該使用DBI/DBD接口。
      PHP
      比PERL易學(xué)。
      使用比PERL少的資源。
      通過升級(jí)到PHP4可以獲得更快的速度。
      C
      MySQL的原生接口。
      較快并賦予更多的控制。
      低層,所以必須付出更多。
      C++
      較高層次,給你更多的時(shí)間來(lái)編寫應(yīng)用。
      仍在開發(fā)中
      ODBC
      運(yùn)行在Windows和Unix上。
      幾乎可在不同的SQL服務(wù)器間移植。
      較慢。MyODBC只是簡(jiǎn)單的直通驅(qū)動(dòng)程序,比用原生接口慢19%。
      有很多方法做同樣的事。很難像很多ODBC驅(qū)動(dòng)程序那樣運(yùn)行,在不同的領(lǐng)域還有不同的錯(cuò)誤。
      問題成堆。Microsoft偶爾還會(huì)改變接口。
      不明朗的未來(lái)。(Microsoft更推崇OLE而非ODBC)
      ODBC
      運(yùn)行在Windows和Unix上。
      幾乎可在不同的SQL服務(wù)器間移植。
      較慢。MyODBC只是簡(jiǎn)單的直通驅(qū)動(dòng)程序,比用原生接口慢19%。
      有很多方法做同樣的事。很難像很多ODBC驅(qū)動(dòng)程序那樣運(yùn)行,在不同的領(lǐng)域還有不同的錯(cuò)誤。
      問題成堆。Microsoft偶爾還會(huì)改變接口。
      不明朗的未來(lái)。(Microsoft更推崇OLE而非ODBC)
      JDBC
      理論上可在不同的操作系統(tǒng)何時(shí)據(jù)庫(kù)間移植。
      可以運(yùn)行在web客戶端。
      Python和其他
      可能不錯(cuò),可我們不用它們。
    六、優(yōu)化應(yīng)用 
      應(yīng)該集中精力解決問題。
      在編寫應(yīng)用時(shí),應(yīng)該決定什么是最重要的:
      速度
      操作系統(tǒng)間的可移植性
      SQL服務(wù)器間的可移植性
      使用持續(xù)的連接。.
      緩存應(yīng)用中的數(shù)據(jù)以減少SQL服務(wù)器的負(fù)載。
      不要查詢應(yīng)用中不需要的列。
      不要使用SELECT * FROM table_name...
      測(cè)試應(yīng)用的所有部分,但將大部分精力放在在可能最壞的合理的負(fù)載下的測(cè)試整體應(yīng)用。通過以一種模塊化的方式進(jìn)行,你應(yīng)該能用一個(gè)快速“啞模塊”替代找到的瓶頸,然后很容易地標(biāo)出下一個(gè)瓶頸。
      如果在一個(gè)批處理中進(jìn)行大量修改,使用LOCK TABLES。例如將多個(gè)UPDATES或DELETES集中在一起。
      
      七、應(yīng)該使用可移植的應(yīng)用 
      Perl DBI/DBD
      ODBC
      JDBC
      Python(或其他有普遍SQL接口的語(yǔ)言)
      你應(yīng)該只使用存在于所有目的SQL服務(wù)器中或可以很容易地用其他構(gòu)造模擬的SQL構(gòu)造。www.mysql.com上的Crash-me頁(yè)可以幫助你。
      為操作系統(tǒng)/SQL服務(wù)器編寫包裝程序來(lái)提供缺少的功能。
      
      八、如果你需要更快的速度,你應(yīng)該:
      找出瓶頸(CPU、磁盤、內(nèi)存、SQL服務(wù)器、操作系統(tǒng)、API或應(yīng)用)并集中全力解決。
      使用給予你更快速度/靈活性的擴(kuò)展。
      逐漸了解SQL服務(wù)器以便能為你的問題使用可能最快的SQL構(gòu)造并避免瓶頸。
      優(yōu)化表布局和查詢。
      使用復(fù)制以獲得更快的選擇(select)速度。
      如果你有一個(gè)慢速的網(wǎng)絡(luò)連接數(shù)據(jù)庫(kù),使用壓縮客戶/服務(wù)器協(xié)議。
      不要害怕時(shí)應(yīng)用的第一個(gè)版本不能完美地移植,在你解決問題時(shí),你總是可以在以后優(yōu)化它。
      
      九、優(yōu)化MySQL 
      挑選編譯器和編譯選項(xiàng)。
      位你的系統(tǒng)尋找最好的啟動(dòng)選項(xiàng)。
      通讀MySQL參考手冊(cè)并閱讀Paul DuBios的《MySQL》一書。(已有中文版-譯注)
      多用EXPLAIN SELECT、SHOW VARIABLES、SHOW STATUS和SHOW PROCESSLIST。
      了解查詢優(yōu)化器的工作原理。
      優(yōu)化表的格式。
      維護(hù)你的表(myisamchk、CHECK TABLE、 OPTIMIZE TABLE)
      使用MySQL的擴(kuò)展功能以讓一切快速完成。
      如果你注意到了你將在很多場(chǎng)合需要某些函數(shù),編寫MySQL UDF函數(shù)。
      不要使用表級(jí)或列級(jí)的GRANT,除非你確實(shí)需要。
      購(gòu)買MySQL技術(shù)支持以幫助你解決問題:)
      
      十、編譯和安裝MySQL 
      通過位你的系統(tǒng)挑選可能最好的編譯器,你通常可以獲得10-30%的性能提高。
      在Linux/Intel平臺(tái)上,用pgcc(gcc的奔騰芯片優(yōu)化版)編譯MySQL。然而,二進(jìn)制代碼將只能運(yùn)行在Intel奔騰CPU上。
      對(duì)于一種特定的平臺(tái),使用MySQL參考手冊(cè)上推薦的優(yōu)化選項(xiàng)。
      一般地,對(duì)特定CPU的原生編譯器(如Sparc的Sun Workshop)應(yīng)該比gcc提供更好的性能,但不總是這樣。
      用你將使用的字符集編譯MySQL。
      靜態(tài)編譯生成mysqld的執(zhí)行文件(用--with-mysqld-ldflags=all-static)并用strip sql/mysqld整理最終的執(zhí)行文件。
      注意,既然MySQL不使用C++擴(kuò)展,不帶擴(kuò)展支持編譯MySQL將贏得巨大的性能提高。
      如果操作系統(tǒng)支持原生線程,使用原生線程(而不用mit-pthreads)。
      用MySQL基準(zhǔn)測(cè)試來(lái)測(cè)試最終的二進(jìn)制代碼。
      
      十一、維護(hù) 
      如果可能,偶爾運(yùn)行一下OPTIMIZE table,這對(duì)大量更新的變長(zhǎng)行非常重要。
      偶爾用myisamchk -a更新一下表中的鍵碼分布統(tǒng)計(jì)。記住在做之前關(guān)掉MySQL。
      如果有碎片文件,可能值得將所有文件復(fù)制到另一個(gè)磁盤上,清除原來(lái)的磁盤并拷回文件。
      如果遇到問題,用myisamchk或CHECK table檢查表。
      用mysqladmin -i10 precesslist extended-status監(jiān)控MySQL的狀態(tài)。
      用MySQL GUI客戶程序,你可以在不同的窗口內(nèi)監(jiān)控進(jìn)程列表和狀態(tài)。
      使用mysqladmin debug獲得有關(guān)鎖定和性能的信息。
      
      十二、優(yōu)化SQL 
      揚(yáng)SQL之長(zhǎng),其它事情交由應(yīng)用去做。使用SQL服務(wù)器來(lái)做:
      
      找出基于WHERE子句的行。
      JOIN表
      GROUP BY
      ORDER BY
      DISTINCT
      不要使用SQL來(lái)做:
      
      檢驗(yàn)數(shù)據(jù)(如日期)
      成為一只計(jì)算器
      技巧:
      
      明智地使用鍵碼。
      鍵碼適合搜索,但不適合索引列的插入/更新。
      保持?jǐn)?shù)據(jù)為數(shù)據(jù)庫(kù)第三范式,但不要擔(dān)心冗余信息或這如果你需要更快的速度,創(chuàng)建總結(jié)表。
      在大表上不做GROUP BY,相反創(chuàng)建大表的總結(jié)表并查詢它。
      UPDATE table set count=count+1 where key_column=constant非常快。
      對(duì)于大表,或許最好偶爾生成總結(jié)表而不是一直保持總結(jié)表。
      充分利用INSERT的默認(rèn)值。
      
      十三、不同SQL服務(wù)器的速度差別(以秒計(jì))
      通過鍵碼讀取2000000行: NT Linux
      mysql 367 249
      mysql_odbc 464
      db2_odbc 1206
      informix_odbc 121126
      ms-sql_odbc 1634
      oracle_odbc 20800
      solid_odbc 877
      sybase_odbc 17614
      
      插入350768行: NT Linux
      mysql 381 206
      mysql_odbc 619
      db2_odbc 3460
      informix_odbc 2692
      ms-sql_odbc 4012
      oracle_odbc 11291
      solid_odbc 1801
      sybase_odbc 4802
      
      在上述測(cè)試中,MySQL配置8M高速緩存運(yùn)行,其他數(shù)據(jù)庫(kù)以默認(rèn)安裝運(yùn)行。
     十四、重要的MySQL啟動(dòng)選項(xiàng) 
      back_log 如果需要大量新連接,修改它。
      thread_cache_size 如果需要大量新連接,修改它。
      key_buffer_size 索引頁(yè)池,可以設(shè)成很大。
      bdb_cache_size BDB表使用的記錄和鍵嗎高速緩存。
      table_cache 如果有很多的表和并發(fā)連接,修改它。
      delay_key_write 如果需要緩存所有鍵碼寫入,設(shè)置它。
      log_slow_queries 找出需花大量時(shí)間的查詢。
      max_heap_table_size 用于GROUP BY
      sort_buffer 用于ORDER BY和GROUP BY
      myisam_sort_buffer_size 用于REPAIR TABLE
      join_buffer_size 在進(jìn)行無(wú)鍵嗎的聯(lián)結(jié)時(shí)使用。
      
      十五、優(yōu)化表 
      MySQL擁有一套豐富的類型。你應(yīng)該對(duì)每一列嘗試使用最有效的類型。
      ANALYSE過程可以幫助你找到表的最優(yōu)類型:SELECT * FROM table_name PROCEDURE ANALYSE()。
      對(duì)于不保存NULL值的列使用NOT NULL,這對(duì)你想索引的列尤其重要。
      將ISAM類型的表改為MyISAM。
      如果可能,用固定的表格式創(chuàng)建表。
      不要索引你不想用的東西。
      利用MySQL能按一個(gè)索引的前綴進(jìn)行查詢的事實(shí)。如果你有索引INDEX(a,b),你不需要在a上的索引。
      不在長(zhǎng)CHAR/VARCHAR列上創(chuàng)建索引,而只索引列的一個(gè)前綴以節(jié)省存儲(chǔ)空間。CREATE TABLE table_name (hostname CHAR(255) not null, index(hostname(10)))
      對(duì)每個(gè)表使用最有效的表格式。
      在不同表中保存相同信息的列應(yīng)該有同樣的定義并具有相同的列名。
      
      十六、MySQL如何次存儲(chǔ)數(shù)據(jù) 
      數(shù)據(jù)庫(kù)以目錄存儲(chǔ)。
      表以文件存儲(chǔ)。
      列以變長(zhǎng)或定長(zhǎng)格式存儲(chǔ)在文件中。對(duì)BDB表,數(shù)據(jù)以頁(yè)面形式存儲(chǔ)。
      支持基于內(nèi)存的表。
      數(shù)據(jù)庫(kù)和表可在不同的磁盤上用符號(hào)連接起來(lái)。
      在Windows上,MySQL支持用.sym文件內(nèi)部符號(hào)連接數(shù)據(jù)庫(kù)。
      
      十七、MySQL表類型 
      HEAP表:固定行長(zhǎng)的表,只存儲(chǔ)在內(nèi)存中并用HASH索引進(jìn)行索引。
      ISAM表:MySQL 3.22中的早期B-tree表格式。
      MyIASM:IASM表的新版本,有如下擴(kuò)展:
      二進(jìn)制層次的可移植性。
      NULL列索引。
      對(duì)變長(zhǎng)行比ISAM表有更少的碎片。
      支持大文件。
      更好的索引壓縮。
      更好的鍵嗎統(tǒng)計(jì)分布。
      更好和更快的auto_increment處理。
      來(lái)自Sleepcat的Berkeley DB(BDB)表:事務(wù)安全(有BEGIN WORK/COMMIT|ROLLBACK)。
      
      十八、MySQL行類型(專指IASM/MyIASM表)
      如果所有列是定長(zhǎng)格式(沒有VARCHAR、BLOB或TEXT),MySQL將以定長(zhǎng)表格式創(chuàng)建表,否則表以動(dòng)態(tài)長(zhǎng)度格式創(chuàng)建。
      定長(zhǎng)格式比動(dòng)態(tài)長(zhǎng)度格式快很多并更安全。
      動(dòng)態(tài)長(zhǎng)度行格式一般占用較少的存儲(chǔ)空間,但如果表頻繁更新,會(huì)產(chǎn)生碎片。
      在某些情況下,不值得將所有VARCHAR、BLOB和TEXT列轉(zhuǎn)移到另一個(gè)表中,只是獲得主表上的更快速度。
      利用myiasmchk(對(duì)ISAM,pack_iasm),可以創(chuàng)建只讀壓縮表,這使磁盤使用率最小,但使用慢速磁盤時(shí),這非常不錯(cuò)。壓縮表充分地利用將不再更新的日志表
      
      十九、MySQL高速緩存(所有線程共享,一次性分配) 
      鍵碼緩存:key_buffer_size,默認(rèn)8M。
      表緩存:table_cache,默認(rèn)64。
      線程緩存:thread_cache_size,默認(rèn)0。
      主機(jī)名緩存:可在編譯時(shí)修改,默認(rèn)128。
      內(nèi)存映射表:目前僅用于壓縮表。
      注意:MySQL沒有行高速緩存,而讓操作系統(tǒng)處理。
      
      二十、MySQL緩存區(qū)變量(非共享,按需分配) 
      sort_buffer:ORDER BY/GROUP BY
      record_buffer:掃描表。
      join_buffer_size:無(wú)鍵聯(lián)結(jié)
      myisam_sort_buffer_size:REPAIR TABLE
      net_buffer_length:對(duì)于讀SQL語(yǔ)句并緩存結(jié)果。
      tmp_table_size:臨時(shí)結(jié)果的HEAP表大小。
      
      二十一、MySQL表高速緩存工作原理 
      每個(gè)MyISAM表的打開實(shí)例(instance)使用一個(gè)索引文件和一個(gè)數(shù)據(jù)文件。如果表被兩個(gè)線程使用或在同一條查詢中使用兩次,MyIASM將共享索引文件而是打開數(shù)據(jù)文件的另一個(gè)實(shí)例。
      如果所有在高速緩存中的表都在使用,緩存將臨時(shí)增加到比表緩存尺寸大些。如果是這樣,下一個(gè)被釋放的表將被關(guān)閉。
      你可以通過檢查mysqld的Opened_tables變量以檢查表緩存是否太小。如果該值太高,你應(yīng)該增大表高速緩存。
      
      二十二、MySQL擴(kuò)展/優(yōu)化-提供更快的速度 
      使用優(yōu)化的表類型(HEAP、MyIASM或BDB表)。
      對(duì)數(shù)據(jù)使用優(yōu)化的列。
      如果可能使用定長(zhǎng)行。
      使用不同的鎖定類型(SELECT HIGH_PRIORITY,INSERT LOW_PRIORITY)
      Auto_increment
      REPLACE (REPLACE INTO table_name VALUES (...))
      INSERT DELAYED
      LOAD DATA INFILE / LOAD_FILE()
      使用多行INSERT一次插入多行。
      SELECT INTO OUTFILE
      LEFT JOIN, STRAIGHT JOIN
      LEFT JOIN ,結(jié)合IS NULL
      ORDER BY可在某些情況下使用鍵碼。
      如果只查詢?cè)谝粋€(gè)索引中的列,將只使用索引樹解決查詢。
      聯(lián)結(jié)一般比子查詢快(對(duì)大多數(shù)SQL服務(wù)器亦如此)。
      LIMIT
      SELECT * from table1 WHERE a > 10 LIMIT 10,20
      DELETE * from table1 WHERE a > 10 LIMIT 10
      foo IN (常數(shù)列表) 高度優(yōu)化。
      GET_LOCK()/RELEASE_LOCK()
      LOCK TABLES
      INSERT和SELECT可同時(shí)運(yùn)行。
      UDF函數(shù)可裝載進(jìn)一個(gè)正在運(yùn)行的服務(wù)器。
      壓縮只讀表。
      CREATE TEMPORARY TABLE
      CREATE TABLE .. SELECT
      帶RAID選項(xiàng)的MyIASM表將文件分割成很多文件以突破某些文件系統(tǒng)的2G限制。
      Delay_keys
      復(fù)制功能
      
      二十二、MySQL何時(shí)使用索引 
      對(duì)一個(gè)鍵碼使用>, >=, =,  1 and key_part1 < 90
      如果使用HEAP表且不用=搜索所有鍵碼部分。
      在HEAP表上使用ORDER BY。
      如果不是用鍵碼第一部分
      
      SELECT * FROM table_name WHERE key_part2=1
      如果使用以一個(gè)通配符開始的LIKE
      
      SELECT * FROM table_name WHERE key_part1 LIKE '%jani%'
      搜索一個(gè)索引而在另一個(gè)索引上做ORDER BY
      
      SELECT * from table_name WHERE key_part1 = # ORDER BY key2
      
      
      二十四、學(xué)會(huì)使用EXPLAIN 
      對(duì)于每一條你認(rèn)為太慢的查詢使用EXPLAIN!
      
      mysql> explain select t3.DateOfAction, t1.TransactionID
      -> from t1 join t2 join t3
      -> where t2.ID = t1.TransactionID and t3.ID = t2.GroupID
      -> order by t3.DateOfAction, t1.TransactionID;
      
      ALL和范圍類型提示一個(gè)潛在的問題。
      
      二十五、學(xué)會(huì)使用SHOW PROCESSLIST 
      使用SHOW processlist來(lái)發(fā)現(xiàn)正在做什么:
      
      在mysql或mysqladmin中用KILL來(lái)殺死溜掉的線程。
      
      二十六、如何知曉MySQL解決一條查詢 
      運(yùn)行項(xiàng)列命令并試圖弄明白其輸出:
      SHOW VARIABLES;
      SHOW COLUMNS FROM ...G
      EXPLAIN SELECT ...G
      FLUSH STATUS;
      SELECT ...;
      SHOW STATUS;
      
      二十七、MySQL非常不錯(cuò) 
      日志
      在進(jìn)行很多連接時(shí),連接非常快。
      同時(shí)使用SELECT和INSERT的場(chǎng)合。
      在不把更新與耗時(shí)太長(zhǎng)的選擇結(jié)合時(shí)。
      在大多數(shù)選擇/更新使用唯一鍵碼時(shí)。
      在使用沒有長(zhǎng)時(shí)間沖突鎖定的多個(gè)表時(shí)。
      在用大表時(shí)(MySQL使用一個(gè)非常緊湊的表格式)。
      
      二十八、MySQL應(yīng)避免的事情 
      用刪掉的行更新或插入表,結(jié)合要耗時(shí)長(zhǎng)的SELECT。
      在能放在WHERE子句中的列上用HAVING。
      不使用鍵碼或鍵碼不夠唯一而進(jìn)行JOIN。
      在不同列類型的列上JOIN。
      在不使用=匹配整個(gè)鍵碼時(shí)使用HEAP表。
      在MySQL監(jiān)控程序中忘記在UPDATE或DELETE中使用一條WHERE子句。如果想這樣做,使用mysql客戶程序的--i-am-a-dummy選項(xiàng)。
      
      二十九、MySQL各種鎖定 
      內(nèi)部表鎖定
      LOCK TABLES(所有表類型適用)
      GET LOCK()/RELEASE LOCK()
      頁(yè)面鎖定(對(duì)BDB表)
      ALTER TABLE也在BDB表上進(jìn)行表鎖定
      LOCK TABLES允許一個(gè)表有多個(gè)讀者和一個(gè)寫者。
      一般WHERE鎖定具有比READ鎖定高的優(yōu)先級(jí)以避免讓寫入方干等。對(duì)于不重要的寫入方,可以使用LOW_PRIORITY關(guān)鍵字讓鎖定處理器優(yōu)選讀取方。
      UPDATE LOW_PRIORITY SET value=10 WHERE id=10;
      
      三十、給MySQL更多信息以更好地解決問題的技巧 
      注意你總能去掉(加注釋)MySQL功能以使查詢可移植:
      
      SELECT /*! SQL_BUFFER_RESULTS */ ...
      SELECT SQL_BUFFER_RESULTS ...
      將強(qiáng)制MySQL生成一個(gè)臨時(shí)結(jié)果集。只要所有臨時(shí)結(jié)果集生成后,所有表上的鎖定均被釋放。這能在遇到表鎖定問題時(shí)或要花很長(zhǎng)時(shí)間將結(jié)果傳給客戶端時(shí)有所幫助。
      SELECT SQL_SMALL_RESULT ... GROUP BY ...
      告訴優(yōu)化器結(jié)果集將只包含很少的行。
      SELECT SQL_BIG_RESULT ... GROUP BY ...
      告訴優(yōu)化器結(jié)果集將包含很多行。
      SELECT STRAIGHT_JOIN ...
      強(qiáng)制優(yōu)化器以出現(xiàn)在FROM子句中的次序聯(lián)結(jié)表。
      SELECT ... FROM table_name [USE INDEX (index_list) | IGNORE INDEX (index_list)] table_name2
      強(qiáng)制MySQL使用/忽略列出的索引。
      
      三十一、事務(wù)的例子 
      MyIASM表如何進(jìn)行事務(wù)處理:
      mysql> LOCK TABLES trans READ, customer WRITE;
      mysql> select sum(value) from trans where customer_id=some_id;
      mysql> update customer set total_value=sum_from_previous_statement
      where customer_id=some_id;
      mysql> UNLOCK TABLES;
      
      BDB表如何進(jìn)行事務(wù):
      mysql> BEGIN WORK;
      mysql> select sum(value) from trans where customer_id=some_id;
      mysql> update customer set total_value=sum_from_previous_statement
      where customer_id=some_id;
      mysql> COMMIT;
      
      注意你可以通過下列語(yǔ)句回避事務(wù):
      UPDATE customer SET value=value+new_value WHERE customer_id=some_id;
      
      三十二、使用REPLACE的例子
      REPLACE的功能極像INSERT,除了如果一條老記錄在一個(gè)唯一索引上具有與新紀(jì)錄相同的值,那么老記錄在新紀(jì)錄插入前則被刪除。不使用
      
      SELECT 1 FROM t1 WHERE key=#
      IF found-row
      LOCK TABLES t1
      DELETE FROM t1 WHERE key1=#
      INSERT INTO t1 VALUES (...)
      UNLOCK TABLES t1;
      ENDIF
      
      而用
      REPLACE INTO t1 VALUES (...)
      
      三十三、一般技巧 
      使用短主鍵。聯(lián)結(jié)表時(shí)使用數(shù)字而非字符串。
      當(dāng)使用多部分鍵碼時(shí),第一部分應(yīng)該時(shí)最常用的部分。
      有疑問時(shí),首先使用更多重復(fù)的列以獲得更好地鍵碼壓縮。
      如果在同一臺(tái)機(jī)器上運(yùn)行MySQL客戶和服務(wù)器,那么在連接MySQL時(shí)則使用套接字而不是TCP/IP(這可以提高性能7.5%)。可在連接MySQL服務(wù)器時(shí)不指定主機(jī)名或主機(jī)名為localhost來(lái)做到。
      如果可能,使用--skip-locking(在某些OS上為默認(rèn)),這將關(guān)閉外部鎖定并將提高性能。
      使用應(yīng)用層哈希值而非長(zhǎng)鍵碼:
      SELECT * FROM table_name WHERE hash=MD5(concat(col1,col2)) AND
      col_1='constant' AND col_2='constant'
      
      在文件中保存需要以文件形式訪問的BLOB,在數(shù)據(jù)庫(kù)中只保存文件名。
      刪除所有行比刪除一大部分行要快。
      如果SQL不夠快,研究一下訪問數(shù)據(jù)的較底層接口。
      
      三十四、使用MySQL 3.23的好處 
      MyISAM:可移植的大表格式
      HEAP:內(nèi)存中的表
      Berkeley DB:支持事務(wù)的表。
      眾多提高的限制
      動(dòng)態(tài)字符集
      更多的STATUS變量
      CHECK和REPAIR表
      更快的GROUP BY和DISTINCT
      LEFT JOIN ... IF NULL的優(yōu)化
      CREATE TABLE ... SELECT
      CREATE TEMPORARY table_name (...)
      臨時(shí)HEAP表到MyISAM表的自動(dòng)轉(zhuǎn)換
      復(fù)制
      mysqlhotcopy腳本
      
      三十五、正在積極開發(fā)的重要功能 
      改進(jìn)事務(wù)處理
      失敗安全的復(fù)制
      正文搜索
      多個(gè)表的刪除(之后完成多個(gè)表的更新)
      更好的鍵碼緩存
      原子RENAME (RENAME TABLE foo as foo_old, foo_new as foo)
      查詢高速緩存
      MERGE TABLES
      一個(gè)更好的GUI客戶程序
    posted @ 2009-03-02 17:59 小馬歌 閱讀(133) | 評(píng)論 (0)編輯 收藏
     

    PHP中的CURL函數(shù)庫(kù)(Client URL Library Function)

    curl_close — 關(guān)閉一個(gè)curl會(huì)話
    curl_copy_handle — 拷貝一個(gè)curl連接資源的所有內(nèi)容和參數(shù)
    curl_errno — 返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的數(shù)字編號(hào)
    curl_error — 返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的字符串
    curl_exec — 執(zhí)行一個(gè)curl會(huì)話
    curl_getinfo — 獲取一個(gè)curl連接資源句柄的信息
    curl_init — 初始化一個(gè)curl會(huì)話
    curl_multi_add_handle — 向curl批處理會(huì)話中添加單獨(dú)的curl句柄資源
    curl_multi_close — 關(guān)閉一個(gè)批處理句柄資源
    curl_multi_exec — 解析一個(gè)curl批處理句柄
    curl_multi_getcontent — 返回獲取的輸出的文本流
    curl_multi_info_read — 獲取當(dāng)前解析的curl的相關(guān)傳輸信息
    curl_multi_init — 初始化一個(gè)curl批處理句柄資源
    curl_multi_remove_handle — 移除curl批處理句柄資源中的某個(gè)句柄資源
    curl_multi_select — Get all the sockets associated with the cURL extension, which can then be "selected"
    curl_setopt_array — 以數(shù)組的形式為一個(gè)curl設(shè)置會(huì)話參數(shù)
    curl_setopt — 為一個(gè)curl設(shè)置會(huì)話參數(shù)
    curl_version — 獲取curl相關(guān)的版本信息

    curl_init()函數(shù)的作用初始化一個(gè)curl會(huì)話,curl_init()函數(shù)唯一的一個(gè)參數(shù)是可選的,表示一個(gè)url地址。
    curl_exec()函數(shù)的作用是執(zhí)行一個(gè)curl會(huì)話,唯一的參數(shù)是curl_init()函數(shù)返回的句柄。
    curl_close()函數(shù)的作用是關(guān)閉一個(gè)curl會(huì)話,唯一的參數(shù)是curl_init()函數(shù)返回的句柄。

    <?php
    $ch = curl_init("http://www.baidu.com/");
    curl_exec($ch);
    curl_close($ch);
    ?>

    curl_version()函數(shù)的作用是獲取curl相關(guān)的版本信息,curl_version()函數(shù)有一個(gè)參數(shù),不清楚是做什么的

    <?php
    print_r(curl_version())
    ?>

    curl_getinfo()函數(shù)的作用是獲取一個(gè)curl連接資源句柄的信息,curl_getinfo()函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是curl的資源句柄,第二個(gè)參數(shù)是下面一些常量:

    <?php
    $ch = curl_init("http://www.baidu.com/");
    print_r(curl_getinfo($ch));
    ?>

    可選的常量包括:

    CURLINFO_EFFECTIVE_URL
    最后一個(gè)有效的url地址

    CURLINFO_HTTP_CODE
    最后一個(gè)收到的HTTP代碼

    CURLINFO_FILETIME
    遠(yuǎn)程獲取文檔的時(shí)間,如果無(wú)法獲取,則返回值為“-1”

    CURLINFO_TOTAL_TIME
    最后一次傳輸所消耗的時(shí)間

    CURLINFO_NAMELOOKUP_TIME
    名稱解析所消耗的時(shí)間

    CURLINFO_CONNECT_TIME
    建立連接所消耗的時(shí)間

    CURLINFO_PRETRANSFER_TIME
    從建立連接到準(zhǔn)備傳輸所使用的時(shí)間

    CURLINFO_STARTTRANSFER_TIME
    從建立連接到傳輸開始所使用的時(shí)間

    CURLINFO_REDIRECT_TIME
    在事務(wù)傳輸開始前重定向所使用的時(shí)間

    CURLINFO_SIZE_UPLOAD
    上傳數(shù)據(jù)量的總值

    CURLINFO_SIZE_DOWNLOAD
    下載數(shù)據(jù)量的總值

    CURLINFO_SPEED_DOWNLOAD
    平均下載速度

    CURLINFO_SPEED_UPLOAD
    平均上傳速度

    CURLINFO_HEADER_SIZE
    header部分的大小

    CURLINFO_HEADER_OUT
    發(fā)送請(qǐng)求的字符串

    CURLINFO_REQUEST_SIZE
    在HTTP請(qǐng)求中有問題的請(qǐng)求的大小

    CURLINFO_SSL_VERIFYRESULT
    Result of SSL certification verification requested by setting CURLOPT_SSL_VERIFYPEER

    CURLINFO_CONTENT_LENGTH_DOWNLOAD
    從Content-Length: field中讀取的下載內(nèi)容長(zhǎng)度

    CURLINFO_CONTENT_LENGTH_UPLOAD
    上傳內(nèi)容大小的說(shuō)明

    CURLINFO_CONTENT_TYPE
    下載內(nèi)容的“Content-type”值,NULL表示服務(wù)器沒有發(fā)送有效的“Content-Type: header”

    curl_setopt()函數(shù)的作用是為一個(gè)curl設(shè)置會(huì)話參數(shù)。curl_setopt_array()函數(shù)的作用是以數(shù)組的形式為一個(gè)curl設(shè)置會(huì)話參數(shù)。

    <?php
    $ch = curl_init();
    $fp = fopen("example_homepage.txt", "w");
    curl_setopt($ch, CURLOPT_FILE, $fp);
    $options = array(
     
    CURLOPT_URL => 'http://www.baidu.com/',
     
    CURLOPT_HEADER => false
     
    );
    curl_setopt_array($ch, $options);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
    ?>

    可設(shè)置的參數(shù)有:

    CURLOPT_AUTOREFERER
    自動(dòng)設(shè)置header中的referer信息

    CURLOPT_BINARYTRANSFER
    在啟用CURLOPT_RETURNTRANSFER時(shí)候?qū)@取數(shù)據(jù)返回

    CURLOPT_COOKIESESSION
    啟用時(shí)curl會(huì)僅僅傳遞一個(gè)session cookie,忽略其他的cookie,默認(rèn)狀況下curl會(huì)將所有的cookie返回給服務(wù)端。session cookie是指那些用來(lái)判斷服務(wù)器端的session是否有效而存在的cookie。

    CURLOPT_CRLF
    啟用時(shí)將Unix的換行符轉(zhuǎn)換成回車換行符。

    CURLOPT_DNS_USE_GLOBAL_CACHE
    啟用時(shí)會(huì)啟用一個(gè)全局的DNS緩存,此項(xiàng)為線程安全的,并且默認(rèn)為true。

    CURLOPT_FAILONERROR
    顯示HTTP狀態(tài)碼,默認(rèn)行為是忽略編號(hào)小于等于400的HTTP信息

    CURLOPT_FILETIME
    啟用時(shí)會(huì)嘗試修改遠(yuǎn)程文檔中的信息。結(jié)果信息會(huì)通過curl_getinfo()函數(shù)的CURLINFO_FILETIME選項(xiàng)返回。

    CURLOPT_FOLLOWLOCATION
    啟用時(shí)會(huì)將服務(wù)器服務(wù)器返回的“Location:”放在header中遞歸的返回給服務(wù)器,使用CURLOPT_MAXREDIRS可以限定遞歸返回的數(shù)量。

    CURLOPT_FORBID_REUSE
    在完成交互以后強(qiáng)迫斷開連接,不能重用。

    CURLOPT_FRESH_CONNECT
    強(qiáng)制獲取一個(gè)新的連接,替代緩存中的連接。

    CURLOPT_FTP_USE_EPRT
    TRUE to use EPRT (and LPRT) when doing active FTP downloads. Use FALSE to disable EPRT and LPRT and use PORT only.
    Added in PHP 5.0.0.

    CURLOPT_FTP_USE_EPSV
    TRUE to first try an EPSV command for FTP transfers before reverting back to PASV. Set to FALSE to disable EPSV.

    CURLOPT_FTPAPPEND
    TRUE to append to the remote file instead of overwriting it.

    CURLOPT_FTPASCII
    An alias of CURLOPT_TRANSFERTEXT. Use that instead.

    CURLOPT_FTPLISTONLY
    TRUE to only list the names of an FTP directory.

    CURLOPT_HEADER
    啟用時(shí)會(huì)將頭文件的信息作為數(shù)據(jù)流輸出。

    CURLOPT_HTTPGET
    啟用時(shí)會(huì)設(shè)置HTTP的method為GET,因?yàn)镚ET是默認(rèn)是,所以只在被修改的情況下使用。

    CURLOPT_HTTPPROXYTUNNEL
    啟用時(shí)會(huì)通過HTTP代理來(lái)傳輸。

    CURLOPT_MUTE
    講curl函數(shù)中所有修改過的參數(shù)恢復(fù)默認(rèn)值。

    CURLOPT_NETRC
    在連接建立以后,訪問~/.netrc文件獲取用戶名和密碼信息連接遠(yuǎn)程站點(diǎn)。

    CURLOPT_NOBODY
    啟用時(shí)將不對(duì)HTML中的body部分進(jìn)行輸出。

    CURLOPT_NOPROGRESS
    啟用時(shí)關(guān)閉curl傳輸?shù)倪M(jìn)度條,此項(xiàng)的默認(rèn)設(shè)置為true

    CURLOPT_NOSIGNAL
    啟用時(shí)忽略所有的curl傳遞給php進(jìn)行的信號(hào)。在SAPI多線程傳輸時(shí)此項(xiàng)被默認(rèn)打開。

    CURLOPT_POST
    啟用時(shí)會(huì)發(fā)送一個(gè)常規(guī)的POST請(qǐng)求,類型為:application/x-www-form-urlencoded,就像表單提交的一樣。

    CURLOPT_PUT
    啟用時(shí)允許HTTP發(fā)送文件,必須同時(shí)設(shè)置CURLOPT_INFILE和CURLOPT_INFILESIZE

    CURLOPT_RETURNTRANSFER
    講curl_exec()獲取的信息以文件流的形式返回,而不是直接輸出。

    CURLOPT_SSL_VERIFYPEER
    FALSE to stop cURL from verifying the peer's certificate. Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option. CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2). TRUE by default as of cURL 7.10. Default bundle installed as of cURL 7.10.

    CURLOPT_TRANSFERTEXT
    TRUE to use ASCII mode for FTP transfers. For LDAP, it retrieves data in plain text instead of HTML. On Windows systems, it will not set STDOUT to binary mode.

    CURLOPT_UNRESTRICTED_AUTH
    在使用CURLOPT_FOLLOWLOCATION產(chǎn)生的header中的多個(gè)locations中持續(xù)追加用戶名和密碼信息,即使域名已發(fā)生改變。

    CURLOPT_UPLOAD
    啟用時(shí)允許文件傳輸

    CURLOPT_VERBOSE
    啟用時(shí)會(huì)匯報(bào)所有的信息,存放在STDERR或指定的CURLOPT_STDERR中

    CURLOPT_BUFFERSIZE
    每次獲取的數(shù)據(jù)中讀入緩存的大小,這個(gè)值每次都會(huì)被填滿。

    CURLOPT_CLOSEPOLICY
    不是CURLCLOSEPOLICY_LEAST_RECENTLY_USED就是CURLCLOSEPOLICY_OLDEST,還存在另外三個(gè),但是curl暫時(shí)還不支持。.

    CURLOPT_CONNECTTIMEOUT
    在發(fā)起連接前等待的時(shí)間,如果設(shè)置為0,則不等待。

    CURLOPT_DNS_CACHE_TIMEOUT
    設(shè)置在內(nèi)存中保存DNS信息的時(shí)間,默認(rèn)為120秒。

    CURLOPT_FTPSSLAUTH
    The FTP authentication method (when is activated): CURLFTPAUTH_SSL (try SSL first), CURLFTPAUTH_TLS (try TLS first), or CURLFTPAUTH_DEFAULT (let cURL decide).

    CURLOPT_HTTP_VERSION
    設(shè)置curl使用的HTTP協(xié)議,CURL_HTTP_VERSION_NONE(讓curl自己判斷),CURL_HTTP_VERSION_1_0(HTTP/1.0),CURL_HTTP_VERSION_1_1(HTTP/1.1)

    CURLOPT_HTTPAUTH
    使用的HTTP驗(yàn)證方法,可選的值有:CURLAUTH_BASIC,CURLAUTH_DIGEST,CURLAUTH_GSSNEGOTIATE,CURLAUTH_NTLM,CURLAUTH_ANY,CURLAUTH_ANYSAFE,可以使用“|”操作符分隔多個(gè)值,curl讓服務(wù)器選擇一個(gè)支持最好的值,CURLAUTH_ANY等價(jià)于CURLAUTH_BASIC | CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM,CURLAUTH_ANYSAFE等價(jià)于CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM

    CURLOPT_INFILESIZE
    設(shè)定上傳文件的大小

    CURLOPT_LOW_SPEED_LIMIT
    當(dāng)傳輸速度小于CURLOPT_LOW_SPEED_LIMIT時(shí),PHP會(huì)根據(jù)CURLOPT_LOW_SPEED_TIME來(lái)判斷是否因太慢而取消傳輸。

    CURLOPT_LOW_SPEED_TIME
    The number of seconds the transfer should be below CURLOPT_LOW_SPEED_LIMIT for PHP to consider the transfer too slow and abort.
    當(dāng)傳輸速度小于CURLOPT_LOW_SPEED_LIMIT時(shí),PHP會(huì)根據(jù)CURLOPT_LOW_SPEED_TIME來(lái)判斷是否因太慢而取消傳輸。

    CURLOPT_MAXCONNECTS
    允許的最大連接數(shù)量,超過是會(huì)通過CURLOPT_CLOSEPOLICY決定應(yīng)該停止哪些連接

    CURLOPT_MAXREDIRS
    指定最多的HTTP重定向的數(shù)量,這個(gè)選項(xiàng)是和CURLOPT_FOLLOWLOCATION一起使用的。

    CURLOPT_PORT
    一個(gè)可選的用來(lái)指定連接端口的量

    CURLOPT_PROXYAUTH
    The HTTP authentication method(s) to use for the proxy connection. Use the same bitmasks as described in CURLOPT_HTTPAUTH. For proxy authentication, only CURLAUTH_BASIC and CURLAUTH_NTLM are currently supported.

    CURLOPT_PROXYPORT
    The port number of the proxy to connect to. This port number can also be set in CURLOPT_PROXY.

    CURLOPT_PROXYTYPE
    Either CURLPROXY_HTTP (default) or CURLPROXY_SOCKS5.

    CURLOPT_RESUME_FROM
    在恢復(fù)傳輸時(shí)傳遞一個(gè)字節(jié)偏移量(用來(lái)斷點(diǎn)續(xù)傳)

    CURLOPT_SSL_VERIFYHOST
    1 to check the existence of a common name in the SSL peer certificate.
    2 to check the existence of a common name and also verify that it matches the hostname provided.

    CURLOPT_SSLVERSION
    The SSL version (2 or 3) to use. By default PHP will try to determine this itself, although in some cases this must be set manually.

    CURLOPT_TIMECONDITION
    如果在CURLOPT_TIMEVALUE指定的某個(gè)時(shí)間以后被編輯過,則使用CURL_TIMECOND_IFMODSINCE返回頁(yè)面,如果沒有被修改過,并且CURLOPT_HEADER為true,則返回一個(gè)"304 Not Modified"的header,CURLOPT_HEADER為false,則使用CURL_TIMECOND_ISUNMODSINCE,默認(rèn)值為CURL_TIMECOND_IFMODSINCE

    CURLOPT_TIMEOUT
    設(shè)置curl允許執(zhí)行的最長(zhǎng)秒數(shù)

    CURLOPT_TIMEVALUE
    設(shè)置一個(gè)CURLOPT_TIMECONDITION使用的時(shí)間戳,在默認(rèn)狀態(tài)下使用的是CURL_TIMECOND_IFMODSINCE

    CURLOPT_CAINFO
    The name of a file holding one or more certificates to verify the peer with. This only makes sense when used in combination with CURLOPT_SSL_VERIFYPEER.

    CURLOPT_CAPATH
    A directory that holds multiple CA certificates. Use this option alongside CURLOPT_SSL_VERIFYPEER.

    CURLOPT_COOKIE
    設(shè)定HTTP請(qǐng)求中“Set-Cookie:”部分的內(nèi)容。

    CURLOPT_COOKIEFILE
    包含cookie信息的文件名稱,這個(gè)cookie文件可以是Netscape格式或者HTTP風(fēng)格的header信息。

    CURLOPT_COOKIEJAR
    連接關(guān)閉以后,存放cookie信息的文件名稱

    CURLOPT_CUSTOMREQUEST
    A custom request method to use instead of "GET" or "HEAD" when doing a HTTP request. This is useful for doing "DELETE" or other, more obscure HTTP requests. Valid values are things like "GET", "POST", "CONNECT" and so on; i.e. Do not enter a whole HTTP request line here. For instance, entering "GET /index.html HTTP/1.0\r\n\r\n" would be incorrect.
    Note: Don't do this without making sure the server supports the custom request method first.

    CURLOPT_EGBSOCKET
    Like CURLOPT_RANDOM_FILE, except a filename to an Entropy Gathering Daemon socket.

    CURLOPT_ENCODING
    header中“Accept-Encoding: ”部分的內(nèi)容,支持的編碼格式為:"identity","deflate","gzip"。如果設(shè)置為空字符串,則表示支持所有的編碼格式

    CURLOPT_FTPPORT
    The value which will be used to get the IP address to use for the FTP "POST" instruction. The "POST" instruction tells the remote server to connect to our specified IP address. The string may be a plain IP address, a hostname, a network interface name (under Unix), or just a plain '-' to use the systems default IP address.

    CURLOPT_INTERFACE
    在外部網(wǎng)絡(luò)接口中使用的名稱,可以是一個(gè)接口名,IP或者主機(jī)名。

    CURLOPT_KRB4LEVEL
    KRB4(Kerberos 4)安全級(jí)別的設(shè)置,可以是一下幾個(gè)值之一:"clear","safe","confidential","private"。默認(rèn)的值為"private",設(shè)置為null的時(shí)候表示禁用KRB4,現(xiàn)在KRB4安全僅能在FTP傳輸中使用。

    CURLOPT_POSTFIELDS
    在HTTP中的“POST”操作。如果要傳送一個(gè)文件,需要一個(gè)@開頭的文件名

    CURLOPT_PROXY
    設(shè)置通過的HTTP代理服務(wù)器

    CURLOPT_PROXYUSERPWD
    連接到代理服務(wù)器的,格式為“[username]:[password]”的用戶名和密碼。

    CURLOPT_RANDOM_FILE
    設(shè)定存放SSL用到的隨機(jī)數(shù)種子的文件名稱

    CURLOPT_RANGE
    設(shè)置HTTP傳輸范圍,可以用“X-Y”的形式設(shè)置一個(gè)傳輸區(qū)間,如果有多個(gè)HTTP傳輸,則使用逗號(hào)分隔多個(gè)值,形如:"X-Y,N-M"。

    CURLOPT_REFERER
    設(shè)置header中"Referer: " 部分的值。

    CURLOPT_SSL_CIPHER_LIST
    A list of ciphers to use for SSL. For example, RC4-SHA and TLSv1 are valid cipher lists.

    CURLOPT_SSLCERT
    傳遞一個(gè)包含PEM格式證書的字符串。

    CURLOPT_SSLCERTPASSWD
    傳遞一個(gè)包含使用CURLOPT_SSLCERT證書必需的密碼。

    CURLOPT_SSLCERTTYPE
    The format of the certificate. Supported formats are "PEM" (default), "DER", and "ENG".

    CURLOPT_SSLENGINE
    The identifier for the crypto engine of the private SSL key specified in CURLOPT_SSLKEY.

    CURLOPT_SSLENGINE_DEFAULT
    The identifier for the crypto engine used for asymmetric crypto operations.

    CURLOPT_SSLKEY
    The name of a file containing a private SSL key.

    CURLOPT_SSLKEYPASSWD
    The secret password needed to use the private SSL key specified in CURLOPT_SSLKEY.
    Note: Since this option contains a sensitive password, remember to keep the PHP script it is contained within safe.

    CURLOPT_SSLKEYTYPE
    The key type of the private SSL key specified in CURLOPT_SSLKEY. Supported key types are "PEM" (default), "DER", and "ENG".

    CURLOPT_URL
    需要獲取的URL地址,也可以在PHP的curl_init()函數(shù)中設(shè)置。

    CURLOPT_USERAGENT
    在HTTP請(qǐng)求中包含一個(gè)”user-agent”頭的字符串。

    CURLOPT_USERPWD
    傳遞一個(gè)連接中需要的用戶名和密碼,格式為:“[username]:[password]”。

    CURLOPT_HTTP200ALIASES
    設(shè)置不再以error的形式來(lái)處理HTTP 200的響應(yīng),格式為一個(gè)數(shù)組。

    CURLOPT_HTTPHEADER
    設(shè)置一個(gè)header中傳輸內(nèi)容的數(shù)組。

    CURLOPT_POSTQUOTE
    An array of FTP commands to execute on the server after the FTP request has been performed.

    CURLOPT_QUOTE
    An array of FTP commands to execute on the server prior to the FTP request.

    CURLOPT_FILE
    設(shè)置輸出文件的位置,值是一個(gè)資源類型,默認(rèn)為STDOUT (瀏覽器)。

    CURLOPT_INFILE
    在上傳文件的時(shí)候需要讀取的文件地址,值是一個(gè)資源類型。

    CURLOPT_STDERR
    設(shè)置一個(gè)錯(cuò)誤輸出地址,值是一個(gè)資源類型,取代默認(rèn)的STDERR。

    CURLOPT_WRITEHEADER
    設(shè)置header部分內(nèi)容的寫入的文件地址,值是一個(gè)資源類型。

    CURLOPT_HEADERFUNCTION
    設(shè)置一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)有兩個(gè)參數(shù),第一個(gè)是curl的資源句柄,第二個(gè)是輸出的header數(shù)據(jù)。header數(shù)據(jù)的輸出必須依賴這個(gè)函數(shù),返回已寫入的數(shù)據(jù)大小。

    CURLOPT_PASSWDFUNCTION
    設(shè)置一個(gè)回調(diào)函數(shù),有三個(gè)參數(shù),第一個(gè)是curl的資源句柄,第二個(gè)是一個(gè)密碼提示符,第三個(gè)參數(shù)是密碼長(zhǎng)度允許的最大值。返回密碼的值。

    CURLOPT_READFUNCTION
    設(shè)置一個(gè)回調(diào)函數(shù),有兩個(gè)參數(shù),第一個(gè)是curl的資源句柄,第二個(gè)是讀取到的數(shù)據(jù)。數(shù)據(jù)讀取必須依賴這個(gè)函數(shù)。返回讀取數(shù)據(jù)的大小,比如0或者EOF。

    CURLOPT_WRITEFUNCTION
    設(shè)置一個(gè)回調(diào)函數(shù),有兩個(gè)參數(shù),第一個(gè)是curl的資源句柄,第二個(gè)是寫入的數(shù)據(jù)。數(shù)據(jù)寫入必須依賴這個(gè)函數(shù)。返回精確的已寫入數(shù)據(jù)的大小

    curl_copy_handle()函數(shù)的作用是拷貝一個(gè)curl連接資源的所有內(nèi)容和參數(shù)

    <?php
    $ch = curl_init("http://www.baidu.com/");
    $another = curl_copy_handle($ch);
    curl_exec($another);
    curl_close($another);
    ?>

    curl_error()函數(shù)的作用是返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的字符串。
    curl_errno()函數(shù)的作用是返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的數(shù)字編號(hào)。

    curl_multi_init()函數(shù)的作用是初始化一個(gè)curl批處理句柄資源。
    curl_multi_add_handle()函數(shù)的作用是向curl批處理會(huì)話中添加單獨(dú)的curl句柄資源。curl_multi_add_handle()函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)表示一個(gè)curl批處理句柄資源,第二個(gè)參數(shù)表示一個(gè)單獨(dú)的curl句柄資源。
    curl_multi_exec()函數(shù)的作用是解析一個(gè)curl批處理句柄,curl_multi_exec()函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)表示一個(gè)批處理句柄資源,第二個(gè)參數(shù)是一個(gè)引用值的參數(shù),表示剩余需要處理的單個(gè)的curl句柄資源數(shù)量。
    curl_multi_remove_handle()函數(shù)表示移除curl批處理句柄資源中的某個(gè)句柄資源,curl_multi_remove_handle()函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)表示一個(gè)curl批處理句柄資源,第二個(gè)參數(shù)表示一個(gè)單獨(dú)的curl句柄資源。
    curl_multi_close()函數(shù)的作用是關(guān)閉一個(gè)批處理句柄資源。

    <?php
    $ch1 = curl_init();
    $ch2 = curl_init();
    curl_setopt($ch1, CURLOPT_URL, "http://www.baidu.com/");
    curl_setopt($ch1, CURLOPT_HEADER, 0);
    curl_setopt($ch2, CURLOPT_URL, "http://www.google.com/");
    curl_setopt($ch2, CURLOPT_HEADER, 0);
    $mh = curl_multi_init();
    curl_multi_add_handle($mh,$ch1);
    curl_multi_add_handle($mh,$ch2);
    do {
     
    curl_multi_exec($mh,$flag);
    } while ($flag > 0);
    curl_multi_remove_handle($mh,$ch1);
    curl_multi_remove_handle($mh,$ch2);
    curl_multi_close($mh);
    ?>

    curl_multi_getcontent()函數(shù)的作用是在設(shè)置了CURLOPT_RETURNTRANSFER的情況下,返回獲取的輸出的文本流。

    curl_multi_info_read()函數(shù)的作用是獲取當(dāng)前解析的curl的相關(guān)傳輸信息。

    curl_multi_select()
    Get all the sockets associated with the cURL extension, which can then be "selected"

    posted @ 2009-03-02 17:59 小馬歌 閱讀(830) | 評(píng)論 (2)編輯 收藏
     
         摘要: <?php /* $Id: config.inc.php,v 1.204.2.1 2003/10/10 14:24:24 nijel Exp $ */ // vim: expandtab sw=4 ts=4 sts=4: /** * phpMyAdmin Configuration File * * All directives are explained in Docume...  閱讀全文
    posted @ 2009-03-02 17:58 小馬歌 閱讀(5938) | 評(píng)論 (1)編輯 收藏
     

     

    版權(quán)聲明:如有轉(zhuǎn)載請(qǐng)求,請(qǐng)注明出處:http://blog.csdn.net/yzhz  楊爭(zhēng)  

            web項(xiàng)目指基于web的開發(fā)項(xiàng)目,由于web開發(fā)的一些特點(diǎn),使得web開發(fā)的項(xiàng)目管理與以往的軟件開發(fā)項(xiàng)目管理有很大的不同,具體表現(xiàn)在
    1、web項(xiàng)目周期短。
            一般的web項(xiàng)目的周期為1~3月,而一般的軟件開發(fā)的周期都在半年以上,象vista微軟花費(fèi)了五年的時(shí)間才開發(fā)出來(lái)。
    2、web項(xiàng)目要求上線快。
            互聯(lián)網(wǎng)公司推出的產(chǎn)品,講究快字當(dāng)頭,誰(shuí)先推出產(chǎn)品占領(lǐng)市場(chǎng),誰(shuí)就取得先機(jī),所以web的項(xiàng)目往往要求上線快,對(duì)于比較大的項(xiàng)目通常我們會(huì)先把產(chǎn)品先launch上線,然后第二期第三期再來(lái)完善。
          “快”應(yīng)該是web開發(fā)和通常的軟件開發(fā)的最大區(qū)別,web產(chǎn)品的維護(hù)是在服務(wù)器端,這就使得這種快成為可能,我們可以很容易地隨時(shí)升級(jí)產(chǎn)品,而通常的軟件由于是部署在用戶的機(jī)器上,升級(jí)的頻率和幅度沒辦法與web產(chǎn)品比擬。
            也正由于這個(gè)“快”,使得web項(xiàng)目的需求變更成為了web項(xiàng)目管理中最需解決的問題。
     
            web項(xiàng)目經(jīng)理手冊(cè)分為若干主題,每個(gè)專題從項(xiàng)目管理的某個(gè)方面介紹項(xiàng)目經(jīng)理在這方面要做的事情,專題會(huì)陸續(xù)推出。
           本手冊(cè)為本人在項(xiàng)目管理中的經(jīng)驗(yàn)總結(jié),所以手冊(cè)的內(nèi)容也會(huì)不斷完善中。

           本手冊(cè)的原則:
    1、指導(dǎo)性強(qiáng)。
    2、實(shí)用性強(qiáng)。
            我一直崇尚這么一句話:把問題復(fù)雜化是為了幫助我們更好地理解這個(gè)問題,而把問題簡(jiǎn)單化是為了讓我們更好地執(zhí)行。所以本手冊(cè)把簡(jiǎn)單可行作為標(biāo)準(zhǔn)。一個(gè)再好的流程如果不簡(jiǎn)單可行,最終也沒法在實(shí)際工作中推廣起來(lái)。當(dāng)然簡(jiǎn)單的含義不是要少做事情,而是所做的事情讓執(zhí)行的人覺得就該怎么做,不這么做,質(zhì)量就沒法保證,并且執(zhí)行起來(lái)很自然。

    對(duì)閱讀者的要求:
    1、本手冊(cè)來(lái)源與本人平時(shí)項(xiàng)目管理的經(jīng)驗(yàn),不同公司有不同的特點(diǎn),項(xiàng)目本身也有差別,本手冊(cè)雖然闡述的是具有普遍性的問題,但是遇到一些具體特殊問題,大家還是要以實(shí)際情況為準(zhǔn),本手冊(cè)可以起到參考作用。

    web項(xiàng)目經(jīng)理手冊(cè)-版本控制流程

            大家在項(xiàng)目過程中是否會(huì)經(jīng)常發(fā)生以下問題:
    1、測(cè)試人員在測(cè)試階段更新測(cè)試環(huán)境時(shí),發(fā)現(xiàn)編譯不通過,或者應(yīng)用出現(xiàn)異常,無(wú)法進(jìn)行測(cè)試。后來(lái)發(fā)現(xiàn)的根源是測(cè)試和開發(fā)共用一個(gè)分支。
    2、有一天某個(gè)人群發(fā)了一條郵件通知,“我們的項(xiàng)目代碼已經(jīng)發(fā)到主干,這段時(shí)間大家不要修改主干信息”,這樣影響其他項(xiàng)目的正常發(fā)布。
    3、項(xiàng)目進(jìn)行了比較長(zhǎng)的時(shí)間,等最后發(fā)布,需要與主干進(jìn)行合并的時(shí)候,出現(xiàn)大量的沖突,幾乎沒法處理。而且沖突處理完后我們還需要重新再做測(cè)試,以保證我們的沖突處理沒有問題,這樣又會(huì)需要花費(fèi)大量的時(shí)間。

     版本控制流程目標(biāo):
    1、保證各個(gè)環(huán)境(開發(fā)、測(cè)試、主干)的獨(dú)立,避免相互影響。
    2、減少最終發(fā)布時(shí)合并主干出現(xiàn)沖突的概率。
    3、降低沖突處理的難度。

    原則:
    多個(gè)版本(開發(fā)版本,測(cè)試版本,發(fā)布版本);多次合并。

    流程:
    1、項(xiàng)目開發(fā)編碼前從當(dāng)前主干建立一條開發(fā)分支,供項(xiàng)目開發(fā)人員使用;
    2、開發(fā)結(jié)束,提交測(cè)試的時(shí)候,從當(dāng)前主干建立一條測(cè)試分支,將開發(fā)分支合并到測(cè)試分支上,供測(cè)試人員進(jìn)行測(cè)試。這樣開發(fā)人員對(duì)開發(fā)分支的修改不會(huì)影響測(cè)試環(huán)境;
    3、bug fix的時(shí)候我們定時(shí)將開發(fā)分支的修改合并到測(cè)試環(huán)境中。
    3、回歸測(cè)試的時(shí)候,從當(dāng)前主干建議一條發(fā)布分支,將測(cè)試分支合并到該發(fā)布分支上,在發(fā)布分支上進(jìn)行回歸測(cè)試。
    4、發(fā)布前,將發(fā)布分支合并到當(dāng)前主干。

    好處:
    1、多個(gè)版本相互獨(dú)立,互不影響
    2、通過多次與主干的合并,這樣發(fā)布時(shí)候和主干做最后一次合并的沖突會(huì)大大減少,并且在與主干多次合并過程中的沖突解決都在測(cè)試階段中得到了測(cè)試。

    建議:
    如果項(xiàng)目的周期比較長(zhǎng),和主干進(jìn)行合并的次數(shù)也應(yīng)該加大,以降低處理沖突的難度。

     

    web項(xiàng)目經(jīng)理手冊(cè)-開發(fā)時(shí)間估算

     

            項(xiàng)目經(jīng)理制定項(xiàng)目時(shí)間表的時(shí)候,需要估算每個(gè)任務(wù)所需的時(shí)間,其中開發(fā)任務(wù)中模塊的分配和時(shí)間估算是其中最主要的部分。本篇專門就這部分作一個(gè)闡述。

    一、在分配模塊和估算開發(fā)時(shí)間時(shí),我們需要把握的原則和目標(biāo):
    1、保證項(xiàng)目整體的進(jìn)度。
    2、有助于確保開發(fā)編碼的質(zhì)量。
    3、有助于提高開發(fā)編碼的速度。


    二、每個(gè)公司都擁有自己的技術(shù)框架,開發(fā)人員主要的工作通常投入在具體的商業(yè)邏輯上。
    通常每個(gè)模塊所需的開發(fā)時(shí)間取決于以下三個(gè)因素:
    1、該模塊的商業(yè)邏輯的復(fù)雜程度。
    2、開發(fā)人員的技術(shù)水平和對(duì)項(xiàng)目所在應(yīng)用的熟悉程度(包括對(duì)框架和應(yīng)用的熟悉程度)。
    3、該模塊技術(shù)實(shí)現(xiàn)上是否有技術(shù)難點(diǎn)。這里我把技術(shù)難點(diǎn)定義為:在現(xiàn)有系統(tǒng)中還未實(shí)現(xiàn)的有一定技術(shù)難點(diǎn)的問題。對(duì)于這樣的難題,開發(fā)者沒有相關(guān)的代碼可以參考,需要投入一些時(shí)間研究解決。

    三、模塊分配和開發(fā)時(shí)間估算的步驟:
    1、作為項(xiàng)目經(jīng)理劃分好模塊后,我會(huì)自己先估算一下每個(gè)模塊所需要的開發(fā)時(shí)間。

    2、召集所有開發(fā)人員,討論模塊分配和開發(fā)時(shí)間估算。
          項(xiàng)目經(jīng)理將劃分好的模塊,讓開發(fā)人員從中挑選他們感興趣的模塊。這樣做可以提高開發(fā)人員的主動(dòng)性和參與性。
          項(xiàng)目經(jīng)理在分配模塊的時(shí)候還需從以下幾方面考慮,以確保開發(fā)的速度和質(zhì)量。
     (1)相同類似的模塊由同一人負(fù)責(zé)開發(fā),比如文章的增刪改由同一開發(fā)者負(fù)責(zé)。這樣做的好處就是開發(fā)者對(duì)相關(guān)邏輯會(huì)更加熟悉,同時(shí)接口的定義也會(huì)比較明確,溝通的成本比較低。
     (2)技術(shù)難度比較大的模塊由技術(shù)水平比較高的人負(fù)責(zé)。
     (3)業(yè)務(wù)邏輯比較復(fù)雜的由對(duì)這塊邏輯比較了解的人負(fù)責(zé)。


     3、模塊分配完后,開發(fā)人員評(píng)估自己負(fù)責(zé)開發(fā)的模塊所需要的時(shí)間。在此過程中我們會(huì)比較詳細(xì)的討論每個(gè)模塊的技術(shù)實(shí)現(xiàn),以便使時(shí)間的估算更加準(zhǔn)確。
     
     4、項(xiàng)目經(jīng)理對(duì)開發(fā)人員估算的時(shí)間進(jìn)行確認(rèn)。
            在確認(rèn)過程中作為項(xiàng)目經(jīng)理我會(huì)參考以上提到的三個(gè)因素,同時(shí)將自己估算的時(shí)間和開發(fā)人員估算的時(shí)間進(jìn)行比較。這其中的差異當(dāng)然會(huì)存在的。對(duì)于那些差異比較大的,我會(huì)和技術(shù)人員探討其中的緣由。
            對(duì)于時(shí)間周期比較長(zhǎng)的任務(wù),我通常會(huì)再細(xì)分一下,爭(zhēng)取每個(gè)任務(wù)的最長(zhǎng)時(shí)間不超過3天。時(shí)間周期越長(zhǎng)的任務(wù),不確定性越高,風(fēng)險(xiǎn)也越高,越有可能成為項(xiàng)目的瓶頸。
     
     
    建議:
    1、項(xiàng)目總結(jié)的時(shí)候,對(duì)項(xiàng)目中的一些數(shù)據(jù)做好統(tǒng)計(jì)比如單位UC所花的開發(fā)時(shí)間、測(cè)試時(shí)間等,這些數(shù)據(jù)統(tǒng)計(jì)可以作為以后開發(fā)的參考。
    2、對(duì)技術(shù)難點(diǎn),在項(xiàng)目開始前做好技術(shù)準(zhǔn)備,提前安排人員研究。這樣會(huì)節(jié)省以后項(xiàng)目時(shí)間,降低技術(shù)風(fēng)險(xiǎn)。

     

    web項(xiàng)目經(jīng)理手冊(cè)-Code Review

     

         Code Review是保證項(xiàng)目中代碼質(zhì)量非常重要的一個(gè)環(huán)節(jié),其主要工作是:
    1、發(fā)現(xiàn)代碼中的bug;
    2、從代碼的易維護(hù)性、可擴(kuò)展性角度考察代碼的質(zhì)量,提出修改建議。

    1、代碼中的bug主要會(huì)出現(xiàn)在下列兩個(gè)地方:
    (1) 與商業(yè)邏輯無(wú)關(guān)的bug。
            比如,系統(tǒng)中打開的流/文件/連接等沒有及時(shí)關(guān)閉;或是存在thread safe問題,或是存在性能低下問題等,這類問題對(duì)有經(jīng)驗(yàn)的開發(fā)人員是比較容易發(fā)現(xiàn)的。

    2、與商業(yè)邏輯相關(guān)的bug。
            這類bug是非常隱蔽的,如果有對(duì)產(chǎn)品不熟悉的人參與該產(chǎn)品的項(xiàng)目開發(fā),容易出現(xiàn)這類的bug。為了避免這類bug的出現(xiàn),我們除了在Use Case和Test Case中詳細(xì)描述以正確指導(dǎo)開發(fā)人員并在測(cè)試時(shí)能及時(shí)發(fā)現(xiàn)它之外,Code Review也是不可缺少的保證環(huán)節(jié)。
            我們希望代碼的審核者對(duì)產(chǎn)品非常熟悉。

    3、什么樣的人承擔(dān)代碼審核者Code Reviewer?
    (1)、比較熟悉相關(guān)商業(yè)邏輯。
    (2)、有豐富的編程經(jīng)驗(yàn)。
    兩者缺一不可。

    4、代碼Code Review的步驟,這些是我在平時(shí)工作中的經(jīng)驗(yàn)總結(jié),目前也是按照這個(gè)步驟在做。
    (1)、代碼編寫者和代碼審核者坐在一起,由代碼編寫者按照UC依次講解自己負(fù)責(zé)的代碼和相關(guān)邏輯,從Web層->DAO層;
    (2)、代碼審核者在此過程中可以隨時(shí)提出自己的疑問,同時(shí)積極發(fā)現(xiàn)隱藏的bug;對(duì)這些bug記錄在案。
    (3)、代碼講解完畢后,代碼審核者給自己安排幾個(gè)小時(shí)再對(duì)代碼審核一遍。
            代碼需要一行一行靜下心看。同時(shí)代碼又要全面的看,以確保代碼整體上設(shè)計(jì)優(yōu)良。

    (4)、代碼審核者根據(jù)審核的結(jié)果編寫“代碼審核報(bào)告”,“審核報(bào)告”中記錄發(fā)現(xiàn)的問題及修改建議,然后把“審核報(bào)告”發(fā)送給相關(guān)人員。

    (5)、代碼編寫者根據(jù)“代碼審核報(bào)告”給出的修改意見,修改好代碼,有不清楚的地方可積極向代碼審核者提出。

    (6)、代碼編寫者 bug fix完畢之后給出反饋。

    (7)、代碼審核者把Code Review中發(fā)現(xiàn)的有價(jià)值的問題更新到"代碼審核規(guī)范"的文檔中,對(duì)于特別值得提醒的問題可群發(fā)email給所有技術(shù)人員。

    5、責(zé)任:
            代碼編寫者,代碼審核者共同對(duì)代碼的質(zhì)量承擔(dān)責(zé)任。這樣才能保證Code Review不是走過場(chǎng),其中代碼編寫者承擔(dān)主要責(zé)任,代碼審核者承擔(dān)次要責(zé)任。

    6、Code Review必備的文檔:
          “代碼審核規(guī)范”文檔:記錄代碼應(yīng)該遵循的標(biāo)準(zhǔn)。代碼審核者根據(jù)這些標(biāo)準(zhǔn)來(lái)Code Review代碼,同時(shí)在Code Review過程中不斷完善該文檔。

    web項(xiàng)目經(jīng)理手冊(cè)-需求變更管理

     

      需求變更管理是web項(xiàng)目管理中最重要的一個(gè)環(huán)節(jié),需求變更管理的有效性直接影響項(xiàng)目的成功與否。

      對(duì)待變更的態(tài)度:
    1、變更是不可避免的。
    2、變更必須被管理。
    3、積極發(fā)現(xiàn)引起變更的因素,促使變更盡可能早的出現(xiàn),減低變更帶來(lái)的風(fēng)險(xiǎn)。

    需求變更管理的目標(biāo):
    1、相關(guān)的干系人必須清楚地了解發(fā)生的變更。
    2、變更處于有效的管理中。
    3、盡量降低變更帶來(lái)的風(fēng)險(xiǎn)。

      通過制定需求變更的流程,確保項(xiàng)目中的需求變更有效地進(jìn)行,實(shí)現(xiàn)上述的目標(biāo)。

      需求變更流程:
    1、確定需求的基準(zhǔn)線。
     通常我們會(huì)以User Case作為需求基準(zhǔn)線,在User Case確認(rèn)之后的任何需求改變,都需要走需求變更流程。沒有走需求變更流程的需求將不被認(rèn)可。

    2、首先項(xiàng)目經(jīng)理接收到需求變更的要求。
      需求變更的提出者可以是項(xiàng)目中的任何人包括產(chǎn)品經(jīng)理、客服、開發(fā)人員、測(cè)試人員等。
     
    3、項(xiàng)目經(jīng)理評(píng)估該需求變更。
      項(xiàng)目經(jīng)理可以召集相關(guān)人員討論該需求變更的合理性、可行性,實(shí)施的代價(jià)以及對(duì)項(xiàng)目的影響。
     項(xiàng)目經(jīng)理作為項(xiàng)目的負(fù)責(zé)人,對(duì)項(xiàng)目的成功負(fù)有主要的責(zé)任。所以需求變更的決策者應(yīng)該由項(xiàng)目經(jīng)理承擔(dān)。
     
    4、需求變更確認(rèn)后由專人將需求變更記錄下來(lái)(格式如下),通知給項(xiàng)目中所有成員。其中以下人員對(duì)需求的變更是緊密相關(guān)的,他們必須知曉并認(rèn)可此需求變更。包括(客戶方代表,需求分析師,測(cè)試人員,相關(guān)開發(fā)人員)。
    需求變更表的格式:

    序號(hào)

    變更提出時(shí)間

    變更描述

    變更類型(是對(duì)原有需求的修改還是新增需求)

    原因

    變更提出者

    開發(fā)人員

    對(duì)進(jìn)度的影響(工作量)

    5、相關(guān)人員接收到確認(rèn)的需求變更后,做以下事情。
    需求分析人員修改需求說(shuō)明書和User Case的相關(guān)內(nèi)容。
    測(cè)試人員修改測(cè)試用例的相關(guān)內(nèi)容。
    開發(fā)人員修改代碼中的相關(guān)部分。

    6、需求凍結(jié)
     項(xiàng)目越到后期,需求變更對(duì)項(xiàng)目的影響就越大,所以在一定時(shí)候我們會(huì)進(jìn)入需求凍結(jié)階段,不再接收需求的變更。

     

    web項(xiàng)目經(jīng)理手冊(cè)-項(xiàng)目經(jīng)理的工作內(nèi)容

     

    一、項(xiàng)目經(jīng)理的目標(biāo)
    1、滿足項(xiàng)目利害關(guān)系者的不同需求。
    清晰明確地了解每一個(gè)項(xiàng)目利害關(guān)系者的需求和期望,投其所好。
    項(xiàng)目利害關(guān)系者包括:項(xiàng)目團(tuán)隊(duì)成員和項(xiàng)目團(tuán)隊(duì)外成員(比如各部門的部門經(jīng)理,客服等)。
    2、保證開發(fā)項(xiàng)目按時(shí)保質(zhì)的完成。

    二、項(xiàng)目經(jīng)理的職責(zé)
    1、建立有效的流程保證項(xiàng)目的順利進(jìn)行。
    2、制定詳細(xì)周密的項(xiàng)目計(jì)劃。
    3、跟蹤,推動(dòng)項(xiàng)目按計(jì)劃進(jìn)行。
    4、積極解決項(xiàng)目過程中出現(xiàn)的問題和沖突。
    5、調(diào)動(dòng)開發(fā)團(tuán)隊(duì)的積極性,創(chuàng)造力,推動(dòng)團(tuán)隊(duì)成員在項(xiàng)目過程中不斷成長(zhǎng)。

    三、項(xiàng)目經(jīng)理的具體工作

    1、項(xiàng)目前期階段
      . 技術(shù)可行性分析,對(duì)項(xiàng)目進(jìn)行技術(shù)評(píng)估、成本評(píng)估以及風(fēng)險(xiǎn)評(píng)估。
     . 與需求方代表進(jìn)行需求討論,明確項(xiàng)目的目標(biāo)、價(jià)值;確定項(xiàng)目范圍、功能及優(yōu)先級(jí)。
      . 組建項(xiàng)目團(tuán)隊(duì),特別要搞清楚項(xiàng)目的key person(對(duì)產(chǎn)品有決定權(quán)的人)。
      . 項(xiàng)目啟動(dòng)會(huì)議。

        通常項(xiàng)目成員包括以下人員:項(xiàng)目經(jīng)理、架構(gòu)師、技術(shù)經(jīng)理、產(chǎn)品經(jīng)理、開發(fā)工程師、DBA、測(cè)試工程師、需求分析工程師、UI、文案、SQA、SCM。
       
    階段輸出物:確認(rèn)后的最終需求文檔
           
    2、分析設(shè)計(jì)階段
    . 制定項(xiàng)目進(jìn)度計(jì)劃,工作任務(wù)分解(WBS)。
    . 資源申請(qǐng)-項(xiàng)目涉及到的開發(fā)資源、測(cè)試資源、設(shè)計(jì)資源。
    . 數(shù)據(jù)庫(kù)設(shè)計(jì)。
    . 系統(tǒng)設(shè)計(jì)。
    . 文檔(包括UC、Demo、TC等)評(píng)審會(huì)議

    階段輸出物:
    (1) User Case
    (2) DEMO
    (3) 系統(tǒng)設(shè)計(jì)文檔
    (4) 數(shù)據(jù)庫(kù)設(shè)計(jì)文檔
    (5) User Case等文檔評(píng)審
     
    3、執(zhí)行階段(開發(fā)、測(cè)試)
    . 準(zhǔn)備開發(fā)環(huán)境、測(cè)試環(huán)境。
    . 跟蹤,推動(dòng)項(xiàng)目按計(jì)劃進(jìn)行。
    . 通報(bào)項(xiàng)目的進(jìn)展情況,通常以周報(bào)的形式。
    . 對(duì)項(xiàng)目的階段成果進(jìn)行評(píng)估,以確保該階段完成的質(zhì)量,包括代碼審核、SQL審核等。
    . 對(duì)需求變更進(jìn)行控制管理。
    . 對(duì)項(xiàng)目風(fēng)險(xiǎn)進(jìn)行管理。
    . 測(cè)試階段客戶驗(yàn)收、收集反饋意見。

    4、發(fā)布階段
    . 制定項(xiàng)目發(fā)布計(jì)劃。
    . 用戶培訓(xùn)。
    . 發(fā)布上線。

    5、上線后監(jiān)控
    . 數(shù)據(jù)監(jiān)控(日志、服務(wù)器狀態(tài))。
    . BUG FIX及改進(jìn)。

    5、結(jié)束階段
    . 項(xiàng)目總結(jié)會(huì)。
    . 產(chǎn)品交付。

     

    web項(xiàng)目經(jīng)理手冊(cè)-項(xiàng)目經(jīng)理需要銘記在心的話

     

    1、項(xiàng)目經(jīng)理不是來(lái)管人的,而是來(lái)支持人的。
            解析:不光是項(xiàng)目經(jīng)理,任何經(jīng)理的職位都是如此。但現(xiàn)實(shí)中很多人并不是那么做,這也是為什么他們沒能把項(xiàng)目做成功的原因。作為項(xiàng)目經(jīng)理首先要端正態(tài)度,認(rèn)識(shí)到這份工作職責(zé)的本質(zhì)。

    2、好的開始是成功的一半。
            解析:一個(gè)好項(xiàng)目的失敗,往往是由于前期的準(zhǔn)備不足、計(jì)劃不周密。所以在項(xiàng)目初期要舍得花時(shí)間做前期的需求收集、討論、技術(shù)準(zhǔn)備等工作。盡管前期的工作看起來(lái)并沒有直接產(chǎn)生效益,但這塊工作做好了,后面的工作往往會(huì)事半功倍。否則前期準(zhǔn)備不足,很可能導(dǎo)致項(xiàng)目出現(xiàn)各種各樣的問題(比如大量的需求變更等)。

    3、什么樣的項(xiàng)目最可能成功?答案是:項(xiàng)目越小成功的可能性越大。
           解析:項(xiàng)目經(jīng)理和相關(guān)人員要仔細(xì)評(píng)估項(xiàng)目中feature的成本/價(jià)值比,盡可能縮小產(chǎn)品的規(guī)模。
          有時(shí)候項(xiàng)目經(jīng)理可能改變不了整個(gè)項(xiàng)目規(guī)模,但是項(xiàng)目經(jīng)理可以采用各種手段來(lái)“縮小”項(xiàng)目,比如分期進(jìn)行、迭代開發(fā)等。
     
    4、任何對(duì)項(xiàng)目的改善無(wú)關(guān)的工作都是浪費(fèi)時(shí)間。
           解析:在項(xiàng)目過程中項(xiàng)目經(jīng)理不要做表面工作,或者對(duì)項(xiàng)目本身無(wú)意義的工作。比如無(wú)休止的會(huì)議;要求編寫詳細(xì)而最終沒有用處的文檔。
     
    5、使用者的參與是項(xiàng)目成功的重要保證。
          解析:使用者可以是:產(chǎn)品經(jīng)理、需求方代表、或者客戶。
          在項(xiàng)目的各個(gè)階段,項(xiàng)目經(jīng)理要積極要求使用者參與到項(xiàng)目過程中。通過這種與使用者不斷的溝通、反饋,使得最終做出來(lái)的產(chǎn)品是客戶真正想要的。

    6、不要認(rèn)為把任務(wù)交給團(tuán)隊(duì)成員,期間你可以不聞不問,到了完成的時(shí)間他自然會(huì)把任務(wù)交上來(lái)。這種想法是非常錯(cuò)誤。
           解析:這樣做無(wú)疑會(huì)增加項(xiàng)目的風(fēng)險(xiǎn),很容易出現(xiàn)該完成的任務(wù)沒有按時(shí)完成,有些延誤,這樣項(xiàng)目后續(xù)的工作都會(huì)收到牽制。
          正確的做法是:當(dāng)把任務(wù)安排下去后,你要定期和成員溝通完成的情況,詢問是否需要支持,這樣我們才能保證任務(wù)能按時(shí)保質(zhì)的完成。

    7、溝通要訣:項(xiàng)目過程中與相關(guān)人員溝通時(shí),不要總認(rèn)為對(duì)方的出發(fā)點(diǎn)都是從項(xiàng)目利益考慮,他/她一定先考慮個(gè)人利益或部門利益,所以項(xiàng)目經(jīng)理要做的是:如何把對(duì)方的個(gè)人利益(部門利益)引導(dǎo)到和項(xiàng)目利益一致。

    8、“加班”是一個(gè)危險(xiǎn)的信號(hào),表明一定是某個(gè)地方出現(xiàn)了問題,要找出進(jìn)度落后的原因。

    9、項(xiàng)目開始前,項(xiàng)目經(jīng)理一定要找出項(xiàng)目的決策者是誰(shuí),誰(shuí)對(duì)項(xiàng)目的產(chǎn)品有最終的發(fā)言權(quán)。

    10、我們交付的不是程序,而是產(chǎn)品和服務(wù)。 

     

    web項(xiàng)目經(jīng)理手冊(cè)-風(fēng)險(xiǎn)管理

     

             風(fēng)險(xiǎn)管理是web項(xiàng)目中項(xiàng)目經(jīng)理最重要的工作之一。風(fēng)險(xiǎn)管理是一個(gè)持續(xù)的過程,貫穿于整個(gè)項(xiàng)目過程中,風(fēng)險(xiǎn)管理包括風(fēng)險(xiǎn)識(shí)別、風(fēng)險(xiǎn)估計(jì)、風(fēng)險(xiǎn)解決以及風(fēng)險(xiǎn)管理策略。
       
            在實(shí)際web項(xiàng)目中,項(xiàng)目風(fēng)險(xiǎn)主要表現(xiàn)為以下情況。了解這些有助于項(xiàng)目經(jīng)理在項(xiàng)目初期就識(shí)別出這些風(fēng)險(xiǎn),并采取措施避免或者減少它們的發(fā)生。

    一、web項(xiàng)目風(fēng)險(xiǎn)列表:
    1:需求變更風(fēng)險(xiǎn):需求已經(jīng)打上了基線,但此后仍然有變更發(fā)生,對(duì)項(xiàng)目造成影響。
           如何減少此類風(fēng)險(xiǎn)的發(fā)生?
    (1) 前期的需求討論要詳細(xì)、充分。需求文檔中需求的范圍要明確、功能描述要清楚。
    (2) 需求文檔中要有demo。對(duì)于web項(xiàng)目,圖片比文字更能說(shuō)明問題。
    (3) 找出項(xiàng)目中需求的決策者(通常會(huì)是產(chǎn)品經(jīng)理、相關(guān)職能主管、客服),所有的需求要經(jīng)過他們的認(rèn)可。
    (4) 客戶在項(xiàng)目過程中的全程參與有助于降低此類風(fēng)險(xiǎn)。需求討論、需求確認(rèn)、User Case確認(rèn)、測(cè)試階段的客戶驗(yàn)收等環(huán)節(jié),都要要求客戶參與。
    (5) 發(fā)生需求變更時(shí),嚴(yán)格按照需求變更流程執(zhí)行。

    2、技術(shù)風(fēng)險(xiǎn):開發(fā)過程中遇到技術(shù)難題,導(dǎo)致開發(fā)時(shí)間延遲或者需求不得不發(fā)生變更。
         如何減少此類風(fēng)險(xiǎn)的發(fā)生?
         在項(xiàng)目開始前的技術(shù)評(píng)估階段,明確技術(shù)難點(diǎn),提前安排人員進(jìn)行攻克。如果在可預(yù)期的時(shí)間內(nèi)無(wú)法解決,可以要求需求方變更需求。

    3、質(zhì)量風(fēng)險(xiǎn):對(duì)于web項(xiàng)目而言,質(zhì)量風(fēng)險(xiǎn)主要指開發(fā)代碼的質(zhì)量。
           如何提高開發(fā)人員開發(fā)的質(zhì)量?
    (1)、制定項(xiàng)目計(jì)劃時(shí),對(duì)開發(fā)時(shí)間的評(píng)估要盡可能的合適。合理的開發(fā)時(shí)間對(duì)開發(fā)質(zhì)量的影響很大。開發(fā)時(shí)間評(píng)估可參考【web項(xiàng)目經(jīng)理手冊(cè)-開發(fā)時(shí)間估算】。
    (2)、有一套嚴(yán)格可行的代碼規(guī)范,編碼時(shí)嚴(yán)格遵守,code review時(shí)嚴(yán)格考核。
    (3)、在編碼前,開發(fā)人員要對(duì)框架熟練掌握。
    (4)、一份好的系統(tǒng)設(shè)計(jì)文檔對(duì)指導(dǎo)開發(fā)非常重要。

    4、資源風(fēng)險(xiǎn):項(xiàng)目所需人力資源無(wú)法按時(shí)到位,導(dǎo)致資源風(fēng)險(xiǎn)。
    如何減少此類風(fēng)險(xiǎn)的發(fā)生?
    這個(gè)就需要在項(xiàng)目計(jì)劃制定的時(shí)候提前申請(qǐng)確認(rèn)資源,并在項(xiàng)目過程中不斷溝通協(xié)調(diào)。

    二、項(xiàng)目風(fēng)險(xiǎn)管理的要點(diǎn):
    1、上述我們所說(shuō)的風(fēng)險(xiǎn)管理都是指可以預(yù)期將要發(fā)生的風(fēng)險(xiǎn),那些不可預(yù)期將要發(fā)生的風(fēng)險(xiǎn)不屬于風(fēng)險(xiǎn)管理的范疇。這也說(shuō)明項(xiàng)目經(jīng)理的經(jīng)驗(yàn)和知識(shí)對(duì)能否管理好風(fēng)險(xiǎn)至關(guān)重要。
    2、詳細(xì)明確的項(xiàng)目計(jì)劃、以及項(xiàng)目執(zhí)行過程中每個(gè)要點(diǎn)的質(zhì)量保證是降低項(xiàng)目風(fēng)險(xiǎn)的必要條件。
    3、風(fēng)險(xiǎn)報(bào)告是項(xiàng)目團(tuán)隊(duì)以及領(lǐng)導(dǎo)了解項(xiàng)目風(fēng)險(xiǎn)的一個(gè)有效手段。
    風(fēng)險(xiǎn)報(bào)告的格式通常是:

      序號(hào) 風(fēng)險(xiǎn)簡(jiǎn)介  對(duì)項(xiàng)目的影響   解決方案(對(duì)策) 

    web項(xiàng)目經(jīng)理手冊(cè)-跨部門合作項(xiàng)目

     

           web項(xiàng)目中有很多項(xiàng)目涉及到跨部門、跨公司的合作。這類項(xiàng)目往往比其他項(xiàng)目更有挑戰(zhàn)。對(duì)于項(xiàng)目經(jīng)理如何做好這些項(xiàng)目呢?
           首先讓我們看看這類項(xiàng)目都有哪些共同的特點(diǎn)。
    1、合作雙方工作在不同地方,對(duì)項(xiàng)目溝通造成一定影響。
    2、合作雙方隸屬于不同的公司或者部門,雙方的項(xiàng)目開發(fā)流程可能完全不同,在項(xiàng)目執(zhí)行過程中需要考慮到這個(gè)因素。
    2、合作項(xiàng)目需要雙方共同完成,如果一方的工作進(jìn)度出現(xiàn)延誤,那么整個(gè)項(xiàng)目的進(jìn)度都會(huì)收到影響。

          本人根據(jù)平時(shí)這類項(xiàng)目的實(shí)施經(jīng)驗(yàn),總結(jié)一下這類項(xiàng)目要想成功,需要把握的原則。
    1、合作雙方的領(lǐng)導(dǎo)層必須都非常重視這個(gè)項(xiàng)目。剃頭挑子一頭熱的項(xiàng)目成功的可能性不會(huì)高。
    只有這樣,項(xiàng)目的優(yōu)先級(jí)才有保證,這樣在以后項(xiàng)目過程中一些資源(包括人力、硬件、時(shí)間投入)更有保證,配合起來(lái)也會(huì)更加順暢。

    2、合作雙方確定好各自的接口人。雙方的溝通都通過接口人進(jìn)行,這樣可以降低成本,提高溝通的效率。
    接口人可以分為兩類:一類是商業(yè)上的接口人,一類是技術(shù)上的接口人。

    3、完備的文檔(接口文檔、數(shù)據(jù)庫(kù)文檔)必不可少。
    web項(xiàng)目雙方的合作在技術(shù)方面通常采用API接口方式交互。所以項(xiàng)目前期詳細(xì)準(zhǔn)確的接口說(shuō)明文檔非常重要,雙方開發(fā)人員之后的開發(fā)都是嚴(yán)格按照接口進(jìn)行。
    同時(shí)接口的相對(duì)穩(wěn)定也是非常重要的,所以需要前期設(shè)計(jì)的時(shí)候認(rèn)真全面地考慮接口規(guī)范。
     
    4、便利的溝通工具。
     對(duì)于跨地區(qū)的合作,便利的溝通工具是非常重要的。當(dāng)然工具最好是免費(fèi),比如使用IM。從溝通方式的效果來(lái)看,我覺得面對(duì)面的溝通>電話溝通>EMAIL(or IM)。

    5、接口變更的及時(shí)通知。
    這一點(diǎn)很重要,接口變更應(yīng)該有流程來(lái)保證,特別是對(duì)于這種成員分散在不同地方的團(tuán)隊(duì)尤為重要。
     
    6、前期技術(shù)方案的溝通。
    前期技術(shù)方案的討論以及接口的定義,最好能當(dāng)面溝通,這樣效果最好。所以前期最好去一趟對(duì)方公司商談這些要點(diǎn)。

    7、各自開發(fā)環(huán)境的可訪問問題。解決雙方開發(fā)環(huán)境的相互調(diào)用問題。
    合作雙方聯(lián)調(diào)的時(shí)候通常需要訪問對(duì)方的接口。由于雙方都在各自環(huán)境進(jìn)行開發(fā),所以需要解決這種問題。
    最好的情況是:可以訪問對(duì)方的環(huán)境(外網(wǎng))。
    最大的風(fēng)險(xiǎn)是:沒有可以聯(lián)調(diào)的環(huán)境,等到發(fā)布到正式環(huán)境上再測(cè)試,這時(shí)候時(shí)間上就有點(diǎn)晚了,可能會(huì)遇到一些之前預(yù)想不到的問題。所以聯(lián)調(diào)的時(shí)間越提前,問題就能越快暴露出來(lái),整個(gè)項(xiàng)目的風(fēng)險(xiǎn)就越小。
    聯(lián)調(diào)環(huán)境的穩(wěn)定也非常重要。有一次我們發(fā)現(xiàn)我們的功能有問題,代碼跟蹤調(diào)試,結(jié)果發(fā)現(xiàn)原來(lái)對(duì)方的環(huán)境有問題,浪費(fèi)了我們很多時(shí)間。

    8、由于項(xiàng)目的各個(gè)點(diǎn)是互相依賴的,所以在一些關(guān)鍵點(diǎn)上要能按時(shí)提交,否則會(huì)影響對(duì)方的進(jìn)度。
    在項(xiàng)目計(jì)劃中要詳細(xì)定義各個(gè)重要的里程碑,并嚴(yán)格控制執(zhí)行。

    9、項(xiàng)目進(jìn)度報(bào)告。
    定時(shí)相互通告項(xiàng)目進(jìn)度,重點(diǎn)關(guān)注項(xiàng)目風(fēng)險(xiǎn)。

    10、熟悉對(duì)方項(xiàng)目開發(fā)的流程。
    不同公司項(xiàng)目的流程、角色分工不一定相同。只有熟悉了對(duì)方項(xiàng)目的流程,在與對(duì)方溝通時(shí)候才能做正確的事情。所謂知己知彼,才能百戰(zhàn)百勝。
    千萬(wàn)不要自己悶頭開發(fā),完全不顧對(duì)方的做事方式,然后自己想當(dāng)然他們應(yīng)該和我們一樣。

     

     web項(xiàng)目經(jīng)理手冊(cè)-你會(huì)溝通嗎?

     

             我們常說(shuō)做好項(xiàng)目的關(guān)鍵之一就是做好“溝通”,但很多人只知道“溝通”的重要性,卻不知道怎么做好“溝通”,所以仍然會(huì)有很多項(xiàng)目由于溝通未做好而導(dǎo)致項(xiàng)目失敗或者有些遺憾。
           “溝通”不僅僅是說(shuō)話,不是說(shuō)的越多溝通就越好。要做好“溝通”關(guān)鍵是清楚以下兩點(diǎn):我們要和誰(shuí)溝通,和他(她)溝通什么,怎么和他(她)溝通。
    溝通的最終目標(biāo)是:讓被溝通的人明白你要傳遞的內(nèi)容,并自覺執(zhí)行好你希望他做的事情。
     
    要解決好溝通問題,我們需要把握以下兩個(gè)原則:
    一、利益原則
             利益原則解決的是“和誰(shuí)溝通”的問題。
    項(xiàng)目開始階段我們要識(shí)別出與項(xiàng)目有利益的人(即項(xiàng)目干系人),確定他們需求和期望,然后采用合適的溝通策略。
      項(xiàng)目的干系人是指參與項(xiàng)目,或其利益在項(xiàng)目執(zhí)行中或成功后受到積極或消極影響的個(gè)
    人和組織。這些人是項(xiàng)目過程中需要著重關(guān)注的人群,很多項(xiàng)目出了問題都是由于忽視了(或者是忘了)其中某些人。
     
       項(xiàng)目干系人通常包括:
    Ø       項(xiàng)目發(fā)起人、出資方。(項(xiàng)目決策者)
    Ø       部門職能經(jīng)理。(資源提供方)
    Ø       項(xiàng)目團(tuán)隊(duì)成員。(項(xiàng)目執(zhí)行者)
    Ø       產(chǎn)品運(yùn)營(yíng)。(產(chǎn)品的運(yùn)營(yíng)者、使用者)
    Ø       客服人員。(客戶接口)
     
     為了更好地把握這一原則,我推薦項(xiàng)目經(jīng)理在項(xiàng)目開始階段使用以下表格。
     

    序號(hào)
    項(xiàng)目干系人
    其對(duì)項(xiàng)目的主要期望
    在本項(xiàng)目中的利益程度
    (H, M, L)
    對(duì)項(xiàng)目的影響程度
    (H, M, L)
    與其溝通的策略
    1
     
     
     
     
     
    2
     
     
     
     
     
    3
     
     
     
     
     
    4
     
     
     
     
     
    5
     
     
     
     
     

     
     
    二、閉環(huán)原則
    很多項(xiàng)目經(jīng)理在實(shí)際溝通中常常會(huì)是這樣的:某某某這個(gè)事情你做一下,或者發(fā)個(gè)郵件給某某,期間也不聞不問,期望到時(shí)候那個(gè)人就會(huì)按時(shí)提交任務(wù)。這種情況往往會(huì)發(fā)生問題。
     
    正確的溝通環(huán)節(jié)應(yīng)該是一個(gè)閉環(huán)。具體的過程應(yīng)該是這樣的:
    1、項(xiàng)目經(jīng)理和項(xiàng)目干系人溝通事情,征詢他們的意見。(雙向溝通)
    2、達(dá)成一致意見,確認(rèn)action列表。(責(zé)任、任務(wù)落實(shí)到具體的人)。
    3、執(zhí)行過程中要跟蹤執(zhí)行情況,確認(rèn)執(zhí)行人是否需要協(xié)助,同時(shí)有助于識(shí)別是否存在潛在的風(fēng)險(xiǎn)發(fā)生。
    4、執(zhí)行結(jié)果的檢查。
        溝通結(jié)束前要注意總結(jié)、回顧,以及action,以確保溝通的效果
     
     
    三、 良好的溝通技巧會(huì)有助于溝通。
    1、當(dāng)你不知道怎么給出建議,或者如何回答的時(shí)候,建議你采用提問式的回答,比如“你覺得怎么做會(huì)好呢?”等等開放式的問題,這樣有助于發(fā)揮大家的積極性,創(chuàng)造性,最終獲得良好的效果。
    2、溝通過程中盡可能少的打斷,不要匆忙下結(jié)論,不要立刻針鋒相對(duì)地駁斥對(duì)方。
    3、要適當(dāng)使用幽默。
    3、積極地給予反饋。
    4、了解溝通者的風(fēng)格,以便更有效的溝通。
     
    四、溝通的表現(xiàn)形式實(shí)際上是很多的,絕不要局限在面對(duì)面對(duì)話,像會(huì)議、email等都是溝通的具體表現(xiàn)。所以上面所說(shuō)的原則和技巧都可以這些環(huán)節(jié)中采用。
     
     
           在項(xiàng)目中如果把握好上面所說(shuō)的原則,再加上自身溝通的技巧,一定會(huì)對(duì)項(xiàng)目的成功起到非常大的幫助。記住和正確的人正確地做正確的事情
     
     
    Web項(xiàng)目經(jīng)理手冊(cè)-組織會(huì)議
     

    組織會(huì)議是項(xiàng)目經(jīng)理日常工作中一項(xiàng)非常重要的工作任務(wù),項(xiàng)目過程中很多重要的決定都是在會(huì)議中做出的,也有很多由于不成功的會(huì)議而對(duì)項(xiàng)目本身造成了不好的影響。

     

    首先我們看看不成功的會(huì)議常常表現(xiàn)為哪些形式:

    1、會(huì)議氛圍不好,參與者發(fā)言不踴躍;

    2、會(huì)議討論常常偏離主題;

    3、會(huì)議沒有取得預(yù)期的結(jié)果;

    4、會(huì)議時(shí)間常常一拖再拖。

    這些不成功的會(huì)議最終的結(jié)果就是:既浪費(fèi)了大家的寶貴時(shí)間又沒有達(dá)到會(huì)議的目的,很多人都經(jīng)歷過這樣的會(huì)議,對(duì)此也是深惡痛絕。

     

    以下是根據(jù)我個(gè)人的經(jīng)驗(yàn),列出了會(huì)議組織者應(yīng)該注意的問題,也可看作組織會(huì)議的最佳實(shí)踐。

     

    在列出最佳實(shí)踐之前有三點(diǎn)我們必須要清楚:

    1、會(huì)議是否會(huì)取得成功很大程度上取決于會(huì)議的組織者。只有組織得有力,會(huì)議才有可能取得成功,這是會(huì)議成功的充分條件。

    2、會(huì)議的組織者和參與者的想法通常是不一致的,有時(shí)候甚至?xí)笙鄰酵?/strong>。所以不要希望會(huì)議的參與者和你一樣,對(duì)會(huì)議有著如此的期待,對(duì)大多數(shù)參與者而言,在會(huì)議中他只是一個(gè)發(fā)表想法的人, 他不用對(duì)會(huì)議的成功承擔(dān)責(zé)任。

    3、以下十一條最佳實(shí)踐是形式上的約定,具體的實(shí)施可以根據(jù)實(shí)際情況來(lái)做。

     

         組織會(huì)議的十一條最佳實(shí)踐

    1、只有需要開會(huì)時(shí)才開會(huì)。有時(shí)候兩三個(gè)人單獨(dú)小范圍溝通會(huì)更加有效。

    2、提前發(fā)出會(huì)議議程,以便會(huì)議參與者知道他們來(lái)做什么。

    3、請(qǐng)對(duì)人很重要,不要把非必要的人召來(lái)開會(huì),當(dāng)然也不要漏掉那些關(guān)鍵人物。在確保必要人物都在的情況下一次會(huì)議參與者越少效果越好。

    4、提前預(yù)約參與者的時(shí)間,以確保他們能按時(shí)到場(chǎng)。

    5、會(huì)議的開場(chǎng)很重要。會(huì)議組織者要在開始前做好幾件事情。通常我建議有幾點(diǎn)要在開場(chǎng)時(shí)說(shuō):

      (1) 再一次強(qiáng)調(diào)會(huì)議的目標(biāo),我們來(lái)做什么。

      (2) 強(qiáng)調(diào)一下會(huì)議的基調(diào)。比如:本次會(huì)議是一個(gè)需求確認(rèn)會(huì),而非需求討論會(huì),主要是討論做還是不做以及告知大家我們要做什么,而不要把太多的精力放在討論如何做上面。

      (3) 說(shuō)明一下會(huì)議的規(guī)則。如要發(fā)言,請(qǐng)舉手;不要有小圈子討論;不要打斷別人的講話,等別人說(shuō)完你再說(shuō)等等。

    6、會(huì)議過程中時(shí)刻注意引導(dǎo)和控制會(huì)議,以確保會(huì)議按照目標(biāo)進(jìn)行。一次會(huì)議的氛圍是否良好,討論是否充分,好的引導(dǎo)至關(guān)重要。比如多提一些開放式的問題。

    7、會(huì)議記錄很重要,把一些結(jié)論和有價(jià)值的內(nèi)容記錄下來(lái),這些是本次會(huì)議的重要成果之一。

    8、會(huì)議要有結(jié)論。我們常在會(huì)議上聽到有人說(shuō):"大家討論了這么半天,結(jié)論呢?"。沒有結(jié)論的會(huì)議是沒有意義的。

    9、會(huì)議后別忘發(fā)會(huì)議紀(jì)要,以及一些Action,什么人什么時(shí)候做什么。

    10、會(huì)議后的action執(zhí)行情況的反饋很重要。反饋是對(duì)會(huì)議參與者的尊重,同時(shí)也告知了會(huì)議的效果。否則會(huì)讓大家感覺到這是一個(gè)可無(wú)可無(wú)的會(huì)議,大家以后參與的積極性也會(huì)降低。很多會(huì)議往往都不注意這一點(diǎn)。

    11、按時(shí)結(jié)束的會(huì)議會(huì)受到所有人的歡迎。

     

          這十一條最佳實(shí)踐,我認(rèn)為適用于項(xiàng)目過程中的大多數(shù)會(huì)議,其他類型的會(huì)議也可以采用。

    posted @ 2009-03-02 17:57 小馬歌 閱讀(472) | 評(píng)論 (0)編輯 收藏
     

    apache DSO模式詳解原理

    那么DSO究竟是什么?事實(shí)上DSO是Dynamic SharedObjects(動(dòng)態(tài)共享目標(biāo))的縮寫,它是現(xiàn)代Unix派生出來(lái)的操作系統(tǒng)都存在著的一種動(dòng)態(tài)連接機(jī)制。它提供了一種在運(yùn)行時(shí)將特殊格式的代碼,在程序運(yùn)行需要時(shí),將需要的部分從外存調(diào)入內(nèi)存執(zhí)行的方法。Apache在1.3以后的版本后開始支持它。因?yàn)锳pache早就使用一個(gè)模塊概念來(lái)擴(kuò)展它的功能并且在內(nèi)部使用一個(gè)基于調(diào)度的列表來(lái)鏈接擴(kuò)展模塊到Apache核心模塊.所以, Apache早就注定要使用DSO來(lái)在運(yùn)行時(shí)加載它的模塊。
    在mod_ssl和mod_rewrite的作者Ralf S. Engelschall(在我看來(lái)他是真正的Apache大師和主要開發(fā)者之一,他的個(gè)人主頁(yè)上 的名篇“Apache 1.3 Dynamic Shared Object (DSO) Support”
    中對(duì)DSO模式的原理有著比較詳盡的敘述(本文基本基于此)。


    讓我們先來(lái)看一下Apache本身的程序結(jié)構(gòu):這是一個(gè)很復(fù)雜的四層結(jié)構(gòu)–每一層構(gòu)建在下一層之上。
    第四層是用Apache模塊開發(fā)的第三方庫(kù)–比如open ssl一般來(lái)說(shuō)在Apache的官方發(fā)行版中這層是空的,但是在實(shí)際的Apache結(jié)構(gòu)中這些庫(kù)構(gòu)成的層結(jié)構(gòu)肯定是存在的。
    第三層是一些可選的附加功能模塊–如mod_ssl,mod_perl。這一層的每個(gè)模塊通常實(shí)現(xiàn)的是Apache的一個(gè)獨(dú)立的分離的功能而事實(shí)上這些模塊沒有一個(gè)是必須的,運(yùn)行一個(gè)最小的Apache不需要任何一個(gè)此層的模塊。
    第二層是Apache的基本功能庫(kù)-這也是Apache的核心本質(zhì)層–這層包括Apache內(nèi)核,http_core(Apache的核心模塊),它們實(shí)現(xiàn)了基本HTTP功能(比如資源處理(通過文件描述符和內(nèi)存段等等),保持預(yù)生成(pre-forked)子進(jìn)程模型,監(jiān)聽已配置的虛擬服務(wù)器的TCP/IP套接字,傳輸HTTP請(qǐng)求流到處理進(jìn)程,處理HTTP協(xié)議狀態(tài),讀寫緩沖,此外還有附加的許多功能比如URL和MIME頭的解析及DSO的裝載等),也提供了Apache的應(yīng)用程序接口(API)(其實(shí)Apache的真正功能還是包含在內(nèi)部模塊中的,為了允許這些模塊完全控制Apache進(jìn)程,內(nèi)核必須提供API接口),這層也包括了一般性的可用代碼庫(kù)(libap)和實(shí)現(xiàn)正則表達(dá)式匹配的庫(kù)(libregex)還有就是一個(gè)小的操作系統(tǒng)的抽象庫(kù)(libos)。
    最低層是與OS相關(guān)的平臺(tái)性應(yīng)用函數(shù),這些OS可以是不同現(xiàn)代UNIX的變種,win32,os/2,MacOS甚至只要是一個(gè)POSIX子系統(tǒng)。
    在這個(gè)復(fù)雜的程序結(jié)構(gòu)中有趣的部分是—事實(shí)上第三層和第四層與第二層之間是松散的連接,而另一方面第三層的模塊間是互相依賴的–因這種結(jié)構(gòu)造成的顯著影響就是第三層和第四層的代碼不能靜態(tài)地連接到最低層平臺(tái)級(jí)的代碼上。因此DSO模式就成了解決它的一種手段。結(jié)合DSO功能,這個(gè)結(jié)構(gòu)就變得很靈活了,可以讓Apache內(nèi)核(從技術(shù)上說(shuō)應(yīng)該是mod_so模塊而不是內(nèi)核)在啟動(dòng)時(shí)(而不是安裝時(shí))裝載必要的部分以實(shí)現(xiàn)第三層和第四層的功能。
    DSO在程序運(yùn)行時(shí)將需要的部分從外存調(diào)入內(nèi)存執(zhí)行存取通常會(huì)有兩種途徑:一種是ld由系統(tǒng)在程序開始時(shí)自動(dòng)載入,這種載入可以由兩種途徑實(shí)現(xiàn):一種是自動(dòng)由系統(tǒng)在可執(zhí)行程序開始時(shí)調(diào)用ld.so來(lái)執(zhí)行。另一種是手動(dòng),是通過在執(zhí)行程序里程序系統(tǒng)界面到Unix裝載程序通過系統(tǒng)調(diào)用tdlopen()/dlsym()來(lái)執(zhí)行的.
    那么具體來(lái)說(shuō)Apache是怎么實(shí)現(xiàn)DSO功能的呢?DSO支持調(diào)用特別的Apache模塊是基于一個(gè)名叫mod_so.c的模塊,這個(gè)模塊必須靜態(tài)的編譯Apache的核心。這是除了http_core.c以外僅有的模塊不可以被放到DSO自己(bootstrapping!)。實(shí)際上所有的別的發(fā)布的Apache模塊都可以被放置到DSO,通過個(gè)別的通過設(shè)置被DSO建立允許–允許可能的-共享設(shè)置(看頂層的INSTALL文件)或者通過改變 AddModule命令在你的src/Configuration到SharedModule命令(看src/INSTALL文件)。
    在編譯一個(gè)模塊到一個(gè)名字叫mod_foo.so的DSO以后,你能夠使用mod_so的LoadModule命令在你的httpd.conf文件里在服務(wù)程序開始時(shí)或重新啟動(dòng)以后調(diào)用這個(gè)模塊。

    為了簡(jiǎn)化這種為了Apache模塊而創(chuàng)建DSO文件的方法(尤其是第三方模塊),一個(gè)新的名叫apxs的支持程序(APacheeXtenSion)被使用.它可以用來(lái)建立基于DSO的模塊,模塊位于Apache源碼樹以外。這個(gè)思路很簡(jiǎn)單:當(dāng)安裝Apache時(shí),設(shè)置使安裝程序安裝Apache C頭文件并且放置平臺(tái)支持的編譯器和鏈接程序標(biāo)志,用來(lái)建立DSO文件到apxs程序。通過這種方法,用戶可以使用apxs來(lái)編譯它的Apache模塊源代碼而不用Apache發(fā)布源代碼樹并且不用手動(dòng)的添加平臺(tái)支持的編譯程序和諒解程序的標(biāo)志來(lái)獲得DSO支持。
    為了放置編譯好的apache核心程序到一個(gè)DSO庫(kù)(僅僅在一些支持的平臺(tái)上需要強(qiáng)迫鏈接程序輸出Apache核心的地址碼–一個(gè)DSO模塊化的先決條件)規(guī)定的SHARED_CORE必須能夠通過設(shè)置–允許-規(guī)定=SHARED_CORE設(shè)置(看頂層的INSTALL文件)或者通過改變Rule命令,在你的Configuration 文件里規(guī)定SHARED_CORE=yes(看src/INSTALL文件).Apache核心代碼接著被放置到一個(gè)名叫l(wèi)ibhttpd.so的DSO庫(kù)。因?yàn)殪o態(tài)庫(kù)不能夠在所有的平臺(tái)上被鏈接成為一個(gè)DSO,一個(gè)附加的名叫 libhttpd.ep的可執(zhí)行程序被創(chuàng)建,這個(gè)程序不但包含這個(gè)靜態(tài)代碼而且有提供main()剩余部分的功能.最后,httpd程序自己被用bootstrapping代碼替換,后者自動(dòng)確定Unix調(diào)度程序能夠裝載并且開始libhttpd.ep,它通過提供LD_LIBRARY_PATH到libhttpd.so的方法實(shí)現(xiàn).
    最后我們?cè)賮?lái)說(shuō)說(shuō)ApacheDSO模式支持的平臺(tái)和它的優(yōu)缺點(diǎn)–應(yīng)該說(shuō)目前DSO模式基本可運(yùn)行在任何unix平臺(tái)上–除了ultrix(因?yàn)樗鼪]有動(dòng)態(tài)(庫(kù))裝載器即:Nodlopen-style interface under thisplatform).它的優(yōu)點(diǎn)是服務(wù)器包能夠在運(yùn)行時(shí)更加靈活并且服務(wù)器包能夠簡(jiǎn)單的用第三方模塊來(lái)擴(kuò)展,那怕是在安裝之后。但同時(shí)DSO模式也有一些缺點(diǎn)如:

    1、不能工作在所有平臺(tái)下比如剛才說(shuō)的不支持動(dòng)態(tài)連接的ultrix。
    2、Apache會(huì)在啟動(dòng)時(shí)慢大約20%,因?yàn)橐鲆恍┣爸米鳂I(yè),而地址碼的解決現(xiàn)在需要UNIX調(diào)度程序來(lái)做。服務(wù)器在某些平臺(tái)在執(zhí)行時(shí)會(huì)慢5%,因?yàn)橄鄬?duì)地址代碼(PIC)有時(shí)在不必要時(shí)也會(huì)需要重新編譯相對(duì)尋址,所以沒有絕對(duì)地址快.因此有時(shí)DSO不會(huì)提高速度。
    3、因?yàn)镈SO模塊會(huì)在個(gè)別平臺(tái)上與別的基于DSO的庫(kù)(ld -lfoo)發(fā)生沖突(例如a.out-based 平臺(tái)經(jīng)常不支持這個(gè)功能,但是ELF-based平臺(tái)支持)你不能為所有類型的模塊使用DSO機(jī)制(即不是所有的DSO模塊都能被加載)。或者換一句話說(shuō),模塊作為DSO文件編譯是受限制,只能使用APACHE核心地址碼,APACHE核心使用的C庫(kù)(libc)和所有的別的動(dòng)態(tài)和靜態(tài)的庫(kù),或者靜態(tài)庫(kù)檔案(libfoo.a)包含的獨(dú)立的代碼。唯一使用別的代碼的辦法是或者確定APACHE核心自己早就包含自己的參考,通過dlopen()調(diào)用代碼自己,或者在建立APACHE時(shí)允許 SHARED_CHAIN規(guī)則(當(dāng)你的平臺(tái)支持不用DSO庫(kù)鏈接DSO文件)。
    在一些平臺(tái)下(許多SVR4系統(tǒng))在鏈接Apache httpd可執(zhí)行程序時(shí)沒有辦法強(qiáng)迫鏈接程序輸出所有全部的DSO所用的地址.但是沒有可見的Apache核心地址碼就沒有標(biāo)準(zhǔn)的Apache模塊能夠作為DSO使用.唯一的辦法是使用SHARED_CORE特性,因?yàn)檫@種方法使全部的地址碼都被強(qiáng)制輸出。作為結(jié)果,Apache src/Configure script自動(dòng)強(qiáng)制SHARED_CORE在這些平臺(tái)上,當(dāng)DSO特性被用在Configuration文件或者在configure命令行.

    posted @ 2009-03-02 17:55 小馬歌 閱讀(204) | 評(píng)論 (0)編輯 收藏
     

    章:   PHP And Socket
    書名: 《PHP Game Programming》
    作者:   Matt Rutledget
    翻譯:   heiyeluren <heiyeluren_gmail_com>

    ◇ Socket基礎(chǔ)
    ◇ 產(chǎn)生一個(gè)服務(wù)器
    ◇  產(chǎn)生一個(gè)客戶端

    在這一章里你將了解到迷人而又讓人容易糊涂的套接字(Sockets)。Sockets在PHP中是沒有充分利用的功能。今天你將看到產(chǎn)生一個(gè)能使用客戶端連接的服務(wù)器,并在客戶端使用socket進(jìn)行連接,服務(wù)器端將詳細(xì)的處理信息發(fā)送給客戶端。
    當(dāng)你看到完整的socket過程,那么你將會(huì)在以后的程序開發(fā)中使用它。這個(gè)服務(wù)器是一個(gè)能讓你連接的HTTP服務(wù)器,客戶端是一個(gè)Web瀏覽器,這是一個(gè)單一的客戶端/服務(wù)器 的關(guān)系。

    ◆ Socket 基礎(chǔ)


    PHP使用Berkley的socket庫(kù)來(lái)創(chuàng)建它的連接。你可以知道socket只不過是一個(gè)數(shù)據(jù)結(jié)構(gòu)。你使用這個(gè)socket數(shù)據(jù)結(jié)構(gòu)去開始一個(gè)客戶端和服務(wù)器之間的會(huì)話。這個(gè)服務(wù)器是一直在監(jiān)聽準(zhǔn)備產(chǎn)生一個(gè)新的會(huì)話。當(dāng)一個(gè)客戶端連接服務(wù)器,它就打開服務(wù)器正在進(jìn)行監(jiān)聽的一個(gè)端口進(jìn)行會(huì)話。這時(shí),服務(wù)器端接受客戶端的連接請(qǐng)求,那么就進(jìn)行一次循環(huán)。現(xiàn)在這個(gè)客戶端就能夠發(fā)送信息到服務(wù)器,服務(wù)器也能發(fā)送信息給客戶端。
    產(chǎn)生一個(gè)Socket,你需要三個(gè)變量:一個(gè)協(xié)議、一個(gè)socket類型和一個(gè)公共協(xié)議類型。產(chǎn)生一個(gè)socket有三種協(xié)議供選擇,繼續(xù)看下面的內(nèi)容來(lái)獲取詳細(xì)的協(xié)議內(nèi)容。
    定義一個(gè)公共的協(xié)議類型是進(jìn)行連接一個(gè)必不可少的元素。下面的表我們看看有那些公共的協(xié)議類型。

    表一:協(xié)議
    名字/常量     描述
    AF_INET  這是大多數(shù)用來(lái)產(chǎn)生socket的協(xié)議,使用TCP或UDP來(lái)傳輸,用在IPv4的地址
    AF_INET6     與上面類似,不過是來(lái)用在IPv6的地址
    AF_UNIX  本地協(xié)議,使用在Unix和Linux系統(tǒng)上,它很少使用,一般都是當(dāng)客戶端和服務(wù)器在同一臺(tái)及其上的時(shí)候使用
    表二:Socket類型
    名字/常量     描述
    SOCK_STREAM  這個(gè)協(xié)議是按照順序的、可靠的、數(shù)據(jù)完整的基于字節(jié)流的連接。這是一個(gè)使用最多的socket類型,這個(gè)socket是使用TCP來(lái)進(jìn)行傳輸。
    SOCK_DGRAM  這個(gè)協(xié)議是無(wú)連接的、固定長(zhǎng)度的傳輸調(diào)用。該協(xié)議是不可靠的,使用UDP來(lái)進(jìn)行它的連接。
    SOCK_SEQPACKET  這個(gè)協(xié)議是雙線路的、可靠的連接,發(fā)送固定長(zhǎng)度的數(shù)據(jù)包進(jìn)行傳輸。必須把這個(gè)包完整的接受才能進(jìn)行讀取。
    SOCK_RAW  這個(gè)socket類型提供單一的網(wǎng)絡(luò)訪問,這個(gè)socket類型使用ICMP公共協(xié)議。(ping、traceroute使用該協(xié)議)
    SOCK_RDM  這個(gè)類型是很少使用的,在大部分的操作系統(tǒng)上沒有實(shí)現(xiàn),它是提供給數(shù)據(jù)鏈路層使用,不保證數(shù)據(jù)包的順序

    表三:公共協(xié)議
    名字/常量     描述
    ICMP  互聯(lián)網(wǎng)控制消息協(xié)議,主要使用在網(wǎng)關(guān)和主機(jī)上,用來(lái)檢查網(wǎng)絡(luò)狀況和報(bào)告錯(cuò)誤信息
    UDP      用戶數(shù)據(jù)報(bào)文協(xié)議,它是一個(gè)無(wú)連接,不可靠的傳輸協(xié)議
    TCP 傳輸控制協(xié)議,這是一個(gè)使用最多的可靠的公共協(xié)議,它能保證數(shù)據(jù)包能夠到達(dá)接受者那兒,如果在傳輸過程中發(fā)生錯(cuò)誤,那么它將重新發(fā)送出錯(cuò)數(shù)據(jù)包。

    現(xiàn)在你知道了產(chǎn)生一個(gè)socket的三個(gè)元素,那么我們就在php中使用socket_create()函數(shù)來(lái)產(chǎn)生一個(gè)socket。這個(gè) socket_create()函數(shù)需要三個(gè)參數(shù):一個(gè)協(xié)議、一個(gè)socket類型、一個(gè)公共協(xié)議。socket_create()函數(shù)運(yùn)行成功返回一個(gè)包含socket的資源類型,如果沒有成功則返回false。
    Resourece socket_create(int protocol, int socketType, int commonProtocol);

    現(xiàn)在你產(chǎn)生一個(gè)socket,然后呢?php提供了幾個(gè)操縱socket的函數(shù)。你能夠綁定socket到一個(gè)IP,監(jiān)聽一個(gè)socket的通信,接受一個(gè)socket;現(xiàn)在我們來(lái)看一個(gè)例子,了解函數(shù)是如何產(chǎn)生、接受和監(jiān)聽一個(gè)socket。

    <?php
    $commonProtocol = getprotobyname(“tcp”);
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, ‘localhost’, 1337);
    socket_listen($socket);
    // More socket functionality to come
    ?>

    上面這個(gè)例子產(chǎn)生一個(gè)你自己的服務(wù)器端。例子第一行,
    $commonProtocol = getprotobyname(“tcp”);
    使用公共協(xié)議名字來(lái)獲取一個(gè)協(xié)議類型。在這里使用的是TCP公共協(xié)議,如果你想使用UDP或者ICMP協(xié)議,那么你應(yīng)該把getprotobyname() 函數(shù)的參數(shù)改為“udp”或“icmp”。還有一個(gè)可選的辦法是不使用getprotobyname()函數(shù)而是指定SOL_TCP或SOL_UDP在 socket_create()函數(shù)中。
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    例子的第二行是產(chǎn)生一個(gè)socket并且返回一個(gè)socket資源的實(shí)例。在你有了一個(gè)socket資源的實(shí)例以后,你就必須把socket綁定到一個(gè)IP地址和某一個(gè)端口上。
    socket_bind($socket, ‘localhost’, 1337);
    在這里你綁定socket到本地計(jì)算機(jī)(127.0.0.1)和綁定socket到你的1337端口。然后你就需要監(jiān)聽所有進(jìn)來(lái)的socket連接。
    socket_listen($socket);
    在第四行以后,你就需要了解所有的socket函數(shù)和他們的使用。

    表四:Socket函數(shù)
    函數(shù)名      描述
    socket_accept()    接受一個(gè)Socket連接
    socket_bind()     把socket綁定在一個(gè)IP地址和端口上
    socket_clear_error()   清除socket的錯(cuò)誤或者最后的錯(cuò)誤代碼
    socket_close()     關(guān)閉一個(gè)socket資源
    socket_connect()    開始一個(gè)socket連接
    socket_create_listen()   在指定端口打開一個(gè)socket監(jiān)聽
    socket_create_pair()   產(chǎn)生一對(duì)沒有區(qū)別的socket到一個(gè)數(shù)組里
    socket_create()    產(chǎn)生一個(gè)socket,相當(dāng)于產(chǎn)生一個(gè)socket的數(shù)據(jù)結(jié)構(gòu)
    socket_get_option()    獲取socket選項(xiàng)
    socket_getpeername()   獲取遠(yuǎn)程類似主機(jī)的ip地址
    socket_getsockname()   獲取本地socket的ip地址
    socket_iovec_add()    添加一個(gè)新的向量到一個(gè)分散/聚合的數(shù)組
    socket_iovec_alloc()   這個(gè)函數(shù)創(chuàng)建一個(gè)能夠發(fā)送接收讀寫的iovec數(shù)據(jù)結(jié)構(gòu)
    socket_iovec_delete()   刪除一個(gè)已經(jīng)分配的iovec
    socket_iovec_fetch()   返回指定的iovec資源的數(shù)據(jù)
    socket_iovec_free()    釋放一個(gè)iovec資源
    socket_iovec_set()    設(shè)置iovec的數(shù)據(jù)新值
    socket_last_error()    獲取當(dāng)前socket的最后錯(cuò)誤代碼
    socket_listen()     監(jiān)聽由指定socket的所有連接
    socket_read()     讀取指定長(zhǎng)度的數(shù)據(jù)
    socket_readv()     讀取從分散/聚合數(shù)組過來(lái)的數(shù)據(jù)
    socket_recv()     從socket里結(jié)束數(shù)據(jù)到緩存
    socket_recvfrom()    接受數(shù)據(jù)從指定的socket,如果沒有指定則默認(rèn)當(dāng)前socket
    socket_recvmsg()    從iovec里接受消息
    socket_select()     多路選擇
    socket_send()     這個(gè)函數(shù)發(fā)送數(shù)據(jù)到已連接的socket
    socket_sendmsg()    發(fā)送消息到socket
    socket_sendto()    發(fā)送消息到指定地址的socket
    socket_set_block()    在socket里設(shè)置為塊模式
    socket_set_nonblock()   socket里設(shè)置為非塊模式
    socket_set_option()    設(shè)置socket選項(xiàng)
    socket_shutdown()    這個(gè)函數(shù)允許你關(guān)閉讀、寫、或者指定的socket
    socket_strerror()    返回指定錯(cuò)誤號(hào)的詳細(xì)錯(cuò)誤
    socket_write()     寫數(shù)據(jù)到socket緩存
    socket_writev()    寫數(shù)據(jù)到分散/聚合數(shù)組

    (注: 函數(shù)介紹刪減了部分原文內(nèi)容,函數(shù)詳細(xì)使用建議參考英文原文,或者參考PHP手冊(cè))


    以上所有的函數(shù)都是PHP中關(guān)于socket的,使用這些函數(shù),你必須把你的socket打開,如果你沒有打開,請(qǐng)編輯你的php.ini文件,去掉下面這行前面的注釋:
    extension=php_sockets.dll
    如果你無(wú)法去掉注釋,那么請(qǐng)使用下面的代碼來(lái)加載擴(kuò)展庫(kù):
    <?php
    if(!extension_loaded(‘sockets’))
    {
    if(strtoupper(substr(PHP_OS, 3)) == “WIN”)
    {
    dl(‘php_sockets.dll’);
    }
    else
    {
    dl(‘sockets.so’);
    }
    }
    ?>

    如果你不知道你的socket是否打開,那么你可以使用phpinfo()函數(shù)來(lái)確定socket是否打開。你通過查看phpinfo信息了解socket是否打開。如下圖:

    查看phpinfo()關(guān)于socket的信息


    ◆ 產(chǎn)生一個(gè)服務(wù)器


    現(xiàn)在我們把第一個(gè)例子進(jìn)行完善。你需要監(jiān)聽一個(gè)指定的socket并且處理用戶的連接。

    <?php
    $commonProtocol = getprotobyname("tcp");
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, 'localhost', 1337);
    socket_listen($socket);
    // Accept any incoming connections to the server
    $connection = socket_accept($socket);
    if($connection)
    {
    socket_write($connection, "You have connected to the socket...\n\r");
    }
    ?>

    你應(yīng)該使用你的命令提示符來(lái)運(yùn)行這個(gè)例子。理由是因?yàn)檫@里將產(chǎn)生一個(gè)服務(wù)器,而不是一個(gè)Web頁(yè)面。如果你嘗試使用Web瀏覽器來(lái)運(yùn)行這個(gè)腳本,那么很有可能它會(huì)超過30秒的限時(shí)。你可以使用下面的代碼來(lái)設(shè)置一個(gè)無(wú)限的運(yùn)行時(shí)間,但是還是建議使用命令提示符來(lái)運(yùn)行。
    set_time_limit(0);
    在你的命令提示符中對(duì)這個(gè)腳本進(jìn)行簡(jiǎn)單測(cè)試:
    Php.exe example01_server.php
    如果你沒有在系統(tǒng)的環(huán)境變量中設(shè)置php解釋器的路徑,那么你將需要給php.exe指定詳細(xì)的路徑。當(dāng)你運(yùn)行這個(gè)服務(wù)器端的時(shí)候,你能夠通過遠(yuǎn)程登陸(telnet)的方式連接到端口1337來(lái)測(cè)試這個(gè)服務(wù)器。如下圖:



    上面的服務(wù)器端有三個(gè)問題:1. 它不能接受多個(gè)連接。2. 它只完成唯一的一個(gè)命令。3. 你不能通過Web瀏覽器連接這個(gè)服務(wù)器。
    這個(gè)第一個(gè)問題比較容易解決,你可以使用一個(gè)應(yīng)用程序去每次都連接到服務(wù)器。但是后面的問題是你需要使用一個(gè)Web頁(yè)面去連接這個(gè)服務(wù)器,這個(gè)比較困難。你可以讓你的服務(wù)器接受連接,然后些數(shù)據(jù)到客戶端(如果它一定要寫的話),關(guān)閉連接并且等待下一個(gè)連接。
    在上一個(gè)代碼的基礎(chǔ)上再改進(jìn),產(chǎn)生下面的代碼來(lái)做你的新服務(wù)器端:

    <?php
    // Set up our socket
    $commonProtocol = getprotobyname("tcp");
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, 'localhost', 1337);
    socket_listen($socket);
    // Initialize the buffer
    $buffer = "NO DATA";
    while(true)
    {
    // Accept any connections coming in on this socket

    $connection = socket_accept($socket);
    printf("Socket connected\r\n");
    // Check to see if there is anything in the buffer
    if($buffer != "")
    {
      printf("Something is in the buffer...sending data...\r\n");
      socket_write($connection, $buffer . "\r\n");
      printf("Wrote to socket\r\n");
    }
    else
    {
      printf("No Data in the buffer\r\n");
    }
    // Get the input
    while($data = socket_read($connection, 1024, PHP_NORMAL_READ))
    {
      $buffer = $data;
      socket_write($connection, "Information Received\r\n");
      printf("Buffer: " . $buffer . "\r\n");
    }
    socket_close($connection);
    printf("Closed the socket\r\n\r\n");
    }
    ?>

    這個(gè)服務(wù)器端要做什么呢?它初始化一個(gè)socket并且打開一個(gè)緩存收發(fā)數(shù)據(jù)。它等待連接,一旦產(chǎn)生一個(gè)連接,它將打印“Socket connected”在服務(wù)器端的屏幕上。這個(gè)服務(wù)器檢查緩沖區(qū),如果緩沖區(qū)里有數(shù)據(jù),它將把數(shù)據(jù)發(fā)送到連接過來(lái)的計(jì)算機(jī)。然后它發(fā)送這個(gè)數(shù)據(jù)的接受信息,一旦它接受了信息,就把信息保存到數(shù)據(jù)里,并且讓連接的計(jì)算機(jī)知道這些信息,最后關(guān)閉連接。當(dāng)連接關(guān)閉后,服務(wù)器又開始處理下一次連接。(翻譯的爛,附上原文)
    This is what the server does. It initializes the socket and the buffer that you use to receive
    and send data. Then it waits for a connection. Once a connection is created it prints
    “Socket connected” to the screen the server is running on. The server then checks to see if
    there is anything in the buffer; if there is, it sends the data to the connected computer.
    After it sends the data it waits to receive information. Once it receives information it stores
    it in the data, lets the connected computer know that it has received the information, and
    then closes the connection. After the connection is closed, the server starts the whole
    process again.


    ◆ 產(chǎn)生一個(gè)客戶端

    處理第二個(gè)問題是很容易的。你需要產(chǎn)生一個(gè)php頁(yè)連接一個(gè)socket,發(fā)送一些數(shù)據(jù)進(jìn)它的緩存并處理它。然后你又個(gè)處理后的數(shù)據(jù)在還頓,你能夠發(fā)送你的數(shù)據(jù)到服務(wù)器。在另外一臺(tái)客戶端連接,它將處理那些數(shù)據(jù)。
    To solve the second problem is very easy. You need to create a PHP page that connects to
    a socket, receive any data that is in the buffer, and process it. After you have processed the
    data in the buffer you can send your data to the server. When another client connects, it
    will process the data you sent and the client will send more data back to the server.


    下面的例子示范了使用socket:

    <?php
    // Create the socket and connect
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $connection = socket_connect($socket,’localhost’, 1337);
    while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
    {
    if($buffer == “NO DATA”)
    {
    echo(“<p>NO DATA</p>”);
    break;
    }
    else
    {
      // Do something with the data in the buffer
      echo(“<p>Buffer Data: “ . $buffer . “</p>”);
    }
    }
    echo(“<p>Writing to Socket</p>”);
    // Write some test data to our socket
    if(!socket_write($socket, “SOME DATA\r\n”))
    {
    echo(“<p>Write failed</p>”);
    }
    // Read any response from the socket
    while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
    {
    echo(“<p>Data sent was: SOME DATA<br> Response was:” . $buffer . “</p>”);
    }
    echo(“<p>Done Reading from Socket</p>”);
    ?>

    這個(gè)例子的代碼演示了客戶端連接到服務(wù)器。客戶端讀取數(shù)據(jù)。如果這是第一時(shí)間到達(dá)這個(gè)循環(huán)的首次連接,這個(gè)服務(wù)器將發(fā)送“NO DATA”返回給客戶端。如果情況發(fā)生了,這個(gè)客戶端在連接之上。客戶端發(fā)送它的數(shù)據(jù)到服務(wù)器,數(shù)據(jù)發(fā)送給服務(wù)器,客戶端等待響應(yīng)。一旦接受到響應(yīng),那么它將把響應(yīng)寫到屏幕上。

    posted @ 2009-03-02 17:55 小馬歌 閱讀(145) | 評(píng)論 (0)編輯 收藏
     

    1、用file_get_contents或者fopen、file、readfile等函數(shù)讀取url的時(shí)候,會(huì)創(chuàng)建一個(gè)名為$http_response_header的變量來(lái)保存http響應(yīng)的報(bào)頭,使用fopen等函數(shù)打開的數(shù)據(jù)流信息可以用stream_get_meta_data來(lái)獲取。
    2、php5中新增的參數(shù)context使這些函數(shù)更加靈活,通過它我們可以定制http請(qǐng)求,甚至post數(shù)據(jù)。


    示例代碼1:

    1. <?php
    2. $html = file_get_contents('http://www.example.com/');
    3. print_r($http_response_header);
    4. // or
    5. $fp = fopen('http://www.example.com/', 'r');
    6. print_r(stream_get_meta_data($fp));
    7. fclose($fp);
    8. ?>

    示例代碼2:

    1. <?php
    2. $data = array ('foo' => 'bar');
    3. $data = http_build_query($data);
    4. $opts = array (
    5.     'http' => array (
    6.         'method' => 'POST',
    7.         'header'=> "Content-type: application/x-www-form-urlencoded\r\n" .
    8.                    "Content-Length: " . strlen($data) . "\r\n",
    9.         'content' => $data
    10.     ),
    11. );
    12. $context = stream_context_create($opts);
    13. $html = file_get_contents('http://www.example.com', false, $context);
    14. echo $html;
    15. ?>

    參考:
    http://cn.php.net/manual/zh/function.file-get-contents.php
    http://cn.php.net/manual/en/function.stream-context-create.php
    http://cn.php.net/manual/zh/wrappers.http.php

    posted @ 2009-03-02 17:54 小馬歌 閱讀(103) | 評(píng)論 (0)編輯 收藏
     
    一、代理服務(wù)器概述
     
    1.1什么是代理服務(wù)器 
    在TCP/IP網(wǎng)絡(luò)中,傳統(tǒng)的通信過程是這樣的:客戶端向服務(wù)器請(qǐng)求數(shù)據(jù),服務(wù)器響應(yīng)該請(qǐng)求,將數(shù)據(jù)傳送給客戶端。在引入了代理服務(wù)器以后,這一過程變成了這樣:客戶端向服務(wù)器發(fā)起請(qǐng)求,該請(qǐng)求被送到代理服務(wù)器;代理服務(wù)器分析該請(qǐng)求,先查看自己緩存中是否有請(qǐng)求數(shù)據(jù),如果有就直接傳送給客戶端,如果沒有就代替客戶端向該服務(wù)器發(fā)出請(qǐng)求。服務(wù)器響應(yīng)以后,代理服務(wù)器將響應(yīng)的數(shù)據(jù)傳送給客戶端,同時(shí)在自己的緩存中保留一份該數(shù)據(jù)的拷貝。這樣,再有客戶端請(qǐng)求相同的數(shù)據(jù)時(shí),代理服務(wù)器就可以直接將數(shù)據(jù)傳送給客戶端,而不需要再向該服務(wù)器發(fā)起請(qǐng)求。
     
    1.2 代理服務(wù)器的功能 
    一般說(shuō)來(lái),代理服務(wù)器具有以下的功能: 
    1.通過緩存增加訪問速度 
    隨著Internet的迅猛發(fā)展,網(wǎng)絡(luò)帶寬變得越來(lái)越珍貴。所以為了提高訪問速度,好多ISP都提供代理服務(wù)器,通過代理服務(wù)器的緩存功能來(lái)加快網(wǎng)絡(luò)的訪問速度。一般說(shuō)來(lái),大多數(shù)的代理服務(wù)器都支持HTTP緩存,但是,有的代理服務(wù)器也支持FTP緩存。在選擇代理服務(wù)器時(shí),對(duì)于大多數(shù)的組織,只需要HTTP緩存功能就足夠了。 
    通常,緩存有主動(dòng)緩存被動(dòng)緩存之分。所謂被動(dòng)緩存,指的是代理服務(wù)器只在客戶端請(qǐng)求數(shù)據(jù)時(shí)才將服務(wù)器返回的數(shù)據(jù)進(jìn)行緩存,如果數(shù)據(jù)過期了,又有客戶端請(qǐng)求相同數(shù)據(jù)時(shí),代理服務(wù)器又必須重新發(fā)起新的數(shù)據(jù)請(qǐng)求,在將響應(yīng)數(shù)據(jù)傳送給客戶端時(shí)又進(jìn)行新的緩存。所謂主動(dòng)緩存,就是代理服務(wù)器不斷地檢查緩存中的數(shù)據(jù),一旦有數(shù)據(jù)過期,則代理服務(wù)器主動(dòng)發(fā)起新的數(shù)據(jù)請(qǐng)求來(lái)更新數(shù)據(jù)。這樣,當(dāng)有客戶端請(qǐng)求該數(shù)據(jù)時(shí)就會(huì)大大縮短響應(yīng)時(shí)間。還需要說(shuō)明的是,對(duì)于數(shù)據(jù)中的認(rèn)證信息,大多數(shù)的代理服務(wù)器都不會(huì)進(jìn)行緩存的。 
    2.提供用私有IP訪問Internet的方法 
    IP地址是不可再生的寶貴資源,假如你只有有限的IP地址,但是需要提供整個(gè)組織的Internet訪問能力,那么,你可以通過使用代理服務(wù)器來(lái)實(shí)現(xiàn)這一點(diǎn)。 
    3.提高網(wǎng)絡(luò)的安全性 
    這一點(diǎn)是很明顯的,如果內(nèi)部用戶訪問Internet都是通過代理服務(wù)器,那么,代理服務(wù)器就成為進(jìn)入Internet的唯一通道;反過來(lái)說(shuō),代理服務(wù)器也是Internet訪問內(nèi)部網(wǎng)的唯一通道,如果你沒有做反向代理,則對(duì)于Internet上的主機(jī)來(lái)說(shuō),你的整個(gè)內(nèi)部網(wǎng)只有代理服務(wù)器是可見的,從而大大增強(qiáng)了網(wǎng)絡(luò)的安全性。 

    1.3 代理服務(wù)器的分類及特點(diǎn) 
    通常的代理服務(wù)器分類方法,是從實(shí)現(xiàn)的機(jī)理分為線路層代理、應(yīng)用層代理、智能線路層代理等等。在這里,我想從另外一個(gè)角度出發(fā),把代理服務(wù)器分為傳統(tǒng)代理服務(wù)器和透明代理服務(wù)器。 
    我認(rèn)為有必要好好搞清楚兩者的區(qū)別,只有真正明白了內(nèi)在地機(jī)理,才能在遇到問題時(shí),有章可循,才不會(huì)一頭霧水,不知從何解決問題。因此,下面我們就通過具體的實(shí)例來(lái)說(shuō)明。本章的寫作思路來(lái)源于Paul Russell所寫的IPCHAINS-HOWTO。下面所舉的例子也來(lái)源于該文章,我覺得我讀該文的最大收獲在于對(duì)內(nèi)部網(wǎng)訪問外部網(wǎng)以及外部網(wǎng)訪問內(nèi)部網(wǎng)的實(shí)現(xiàn)手段有了一個(gè)清晰的認(rèn)識(shí)。當(dāng)然,這里所謂的內(nèi)部網(wǎng)是指使用私有IP的內(nèi)部網(wǎng)絡(luò)。 
    我們的例子都基于以下假設(shè): 
    你的域名為sample.com,你的內(nèi)部網(wǎng)(192.168.1.*)用戶通過proxy.sample.com(外部接口 eth0:1.2.3.4;內(nèi)部接口 eth1:192.168.1.1)的代理服務(wù)器訪問Internet,換句話說(shuō),該代理服務(wù)器是唯一一臺(tái)直接與Internet和內(nèi)部網(wǎng)相連的機(jī)器。并假該設(shè)代理服務(wù)器上運(yùn)行著某種代理服務(wù)器軟件(如squid)。假設(shè)內(nèi)部網(wǎng)中某一客戶機(jī)為client.sample.com(192.168.1.100)。 
    +-------------------+ 
    |內(nèi)部網(wǎng)(192.168.1.*)| eth1+--------+eth0 DDN 
    | +------------| proxy |<===============>Internet 
    |client198.168.1.100| +--------+ 
    +-------------------+ 
    eth0: 1.2.3.4 
    eth1: 198.168.1.1 

    1.3.1傳統(tǒng)代理 
    在以上基礎(chǔ)上我們做以下工作: 
    1.代理服務(wù)軟件被綁定到代理服務(wù)器的8080端口。 
    2.客戶端瀏覽器被配置使用代理服務(wù)器的8080端口。 
    3.客戶端不需要配置DNS。 
    4.代理服務(wù)器上需要配置代理服務(wù)器。 
    5.客戶端不需要配置缺省路由。 
    當(dāng)我們?cè)诳蛻舳藶g覽器中打開一個(gè)web請(qǐng)求,比如“http://www.linuxaid.com.cn”,這時(shí)將陸續(xù)發(fā)生以下事件: 
    1.客戶端使用某一端口(比如1025)連接代理服務(wù)器8080端口,請(qǐng)求web頁(yè)面“http://www.linuxaid.com.cn” 
    2.代理服務(wù)器向DNS請(qǐng)求“www.linuxaid.com.cn”,得到相應(yīng)的IP地址202.99.11.120。然后,代理服務(wù)器使用某一端口(比如1037)向該IP地址的80端口發(fā)起web連接請(qǐng)求,請(qǐng)求web頁(yè)面。 
    3.收到響應(yīng)的web頁(yè)面后,代理服務(wù)器把該數(shù)據(jù)傳送給客戶端。 
    4.客戶端瀏覽器顯示該頁(yè)面。 
    從www.linuxaid.com.cn的角度看來(lái),連接是在1.2.3.4地1037端口和202.99.11.120的80端口之間建立的。從client的角度看來(lái),連接是在192.168.1.100的1025端口和1.2.3.4的8080端口之間建立的。
     
    1.3.2 透明代理 
    透明代理的意思是客戶端根本不需要知道有代理服務(wù)器的存在。 
    在以上基礎(chǔ)上我們做以下工作: 
    1.配置透明代理服務(wù)器軟件運(yùn)行在代理服務(wù)器的8080端口。 
    2.配置代理服務(wù)器將所有對(duì)80端口的連接重定向到8080端口。 
    3.配置客戶端瀏覽器直接連解到Internet。 
    4.在客戶端配置好DNS. 
    5.配置客戶端的缺省網(wǎng)關(guān)為192.168.1.1. 
    當(dāng)我們?cè)诳蛻舳藶g覽器中打開一個(gè)web請(qǐng)求,比如“http://www.linuxaid.com.cn”,這時(shí)將陸續(xù)發(fā)生以下事件: 
    1.客戶端向DNS請(qǐng)求“www.linuxaid.com.cn”,得到相應(yīng)的IP地址202.99.11.120。然后,客戶端使用某一端口(比如1066)向該IP地址的80端口發(fā)起web連接請(qǐng)求,請(qǐng)求web頁(yè)面。 
    2.當(dāng)該請(qǐng)求包通過透明代理服務(wù)器時(shí),被重定向到代理服務(wù)器的綁定端口8080。于是,透明代理服務(wù)器用某一端口(比如1088)向202.99.11.120的80端口發(fā)起web連接請(qǐng)求,請(qǐng)求web頁(yè)面。 
    3.收到響應(yīng)的web頁(yè)面后,代理服務(wù)器把該數(shù)據(jù)傳送給客戶端。 
    4.客戶端瀏覽器顯示該頁(yè)面。 
    從www.linuxaid.com.cn的角度看來(lái),連接是在1.2.3.4地1088端口和202.99.11.120的80端口之間建立的。從client的角度看來(lái),連接是在192.168.1.100的1066端口和202.99.11.120的80端口之間建立的。 
    以上就是傳統(tǒng)代理服務(wù)器和透明代理服務(wù)器的區(qū)別所在。 

    二、各種代理服務(wù)器的比較 
    linux下的代理服務(wù)器軟件很多,我從www.freshmeat.com(一個(gè)著名的linux軟件站點(diǎn))查看了一下,足有六十多個(gè)。但是被廣泛應(yīng)用的只有Apache、socks、squid等幾個(gè)實(shí)踐證明是高性能的代理軟件。下面我們分別來(lái)比較一下這幾個(gè)軟件: 

    2.1 Apache 
    Apache是世界上用的最廣泛的HTTP服務(wù)器,之所以用的最廣泛,是因?yàn)樗鼜?qiáng)大的功能、高效率、安全性和速度。從1.1.x版本開始,Apache開始包含了一個(gè)代理模塊。用Apache作代理服務(wù)器的性能優(yōu)勢(shì)并不明顯,不建議使用。 

    2.2 Socks 
    Socks是一種網(wǎng)絡(luò)代理協(xié)議,該協(xié)議可以讓客戶機(jī)通過Socks服務(wù)器獲得對(duì)Internet的完全訪問能力。Scoks在服務(wù)器和客戶端之間建立一個(gè)安全的代理數(shù)據(jù)通道,從客戶的角度看來(lái),Scoks是透明的;從服務(wù)器的角度看來(lái),Socks就是客戶端。客戶端不需要具有對(duì)Internet的直接訪問能力(也就是說(shuō),可以使用私有IP地址),因?yàn)镾ocks服務(wù)器能夠把來(lái)自于客戶端的連接請(qǐng)求重定向到Internet。此外,Socks服務(wù)器可以對(duì)用戶連接請(qǐng)求進(jìn)行認(rèn)證,允許合法用戶建立代理連接。同理,Socks也能防止非授權(quán)的Internet用戶訪問及的內(nèi)部網(wǎng)絡(luò)。所以常常把Socks當(dāng)作防火墻來(lái)使用。 
    常見的瀏覽器如netscape、IE等可以直接使用Socks, 并且我們也可以使用socsk5的所帶的client來(lái)使那些不直接支持socks的internet軟件使用Socks。 
    更多的資料可以參考Socks官方站點(diǎn)http://www.socks.nec.com。 

    2.3 Squid 
    對(duì)于web用戶來(lái)說(shuō),Squid是一個(gè)高性能的代理緩存服務(wù)器,Squid支持FTP、gopher和HTTP協(xié)議。和一般的代理緩存軟件不同,Squid用一個(gè)單獨(dú)的、非模塊化的、I/O驅(qū)動(dòng)的進(jìn)程來(lái)處理所有的客戶端請(qǐng)求。 
    Squid將數(shù)據(jù)元緩存在內(nèi)存中,同時(shí)也緩存DNS查詢的結(jié)果,除此之外,它還支持非模塊化的DNS查詢,對(duì)失敗的請(qǐng)求進(jìn)行消極緩存。Squid支持SSL,支持訪問控制。由于使用了ICP(輕量Internet緩存協(xié)議),Squid能夠?qū)崿F(xiàn)層疊的代理陣列,從而最大限度地節(jié)約帶寬。 
    Squid由一個(gè)主要的服務(wù)程序squid,一個(gè)DNS查詢程序dnsserver,幾個(gè)重寫請(qǐng)求和執(zhí)行認(rèn)證的程序,以及幾個(gè)管理工具組成。當(dāng)Squid啟動(dòng)以后,它可以派生出預(yù)先指定數(shù)目的dnsserver進(jìn)程,而每一個(gè)dnsserver進(jìn)程都可以執(zhí)行單獨(dú)的DNS查詢,這樣一來(lái)就大大減少了服務(wù)器等待DNS查詢的時(shí)間。 

    2.4 選擇 
    從上面的比較可以看出,Apache主要功能是web服務(wù)器,代理功能只不過是其一個(gè)模塊而已,Socks雖然強(qiáng)大,但有欠靈活,因此我們著重推薦你使用Squid。下面的章節(jié)我們就一起來(lái)學(xué)習(xí)Squid激動(dòng)人心的特性及相關(guān)的安裝與配置。

    三、安裝Squid Proxy Server 

    3.1獲取軟件 
    你可以通過以下途徑獲取該軟件: 
    1.從Squid的官方站點(diǎn)http://www.squid-cache.org下載該軟件; 
    2.從你的linux發(fā)行版本中獲取該軟件; 
    通常,Squid軟件包有兩種:一種是源代碼,下載后需要自己重新編譯;可執(zhí)行文件,下載后只需解壓就可以使用;另一種是就是RedHat所使用的rpm包。下面我們分別講講這兩種軟件包的安裝方法。 

    3.2安裝軟件 
    我們以目前最新的穩(wěn)定版本squid-2.3.STABLEX為例。 

    3.2.1rpm包的安裝 
    1.進(jìn)入/mnt/cdrom/RedHat/RPMS 
    2.執(zhí)行rpm -ivh squid-2.2.STABLE4-8.i386.rpm。 
    當(dāng)然,我們也可以在開始安裝系統(tǒng)的過程中安裝該軟件。 

    3.2.2 源代碼包的安裝 
    1.從http://www.squid-cache.org下載squid-2.3.STABLE2-src.tar.gz。 
    2.將該文件拷貝到/usr/local目錄。 
    3.解開該文件 tar xvzf squid-2.3.STABLE2-src.tar.gz。 
    4.解開后,在/usr/local生成一個(gè)新的目錄squid-2.3.STABLE2,為了方便用mv命令將 該目錄重命名為squid mv squid-2.3.STABLE2 squid; 
    5.進(jìn)入squid cd squid 
    6.執(zhí)行./configure 可以用./confgure --prefix=/directory/you/want指定安裝目錄 
    系統(tǒng)缺省安裝目錄為/usr/local/squid。 
    7.執(zhí)行 make all 
    8.執(zhí)行 make install 
    9.安裝結(jié)束后,squid的可執(zhí)行文件在安裝目錄的bin子目錄下,配置文件在etc子目錄下。 

    四、配置squid基礎(chǔ)篇——讓代理服務(wù)器跑起來(lái) 
    由于RedHat各方面的優(yōu)勢(shì)(包括易用性,穩(wěn)定性等等),全世界范圍內(nèi)使用該發(fā)行版的用戶比較多,所以,我們下面的說(shuō)明都是以RedHat6.1環(huán)境下squid-2.2.STABLE4-8版本為主。從我的使用經(jīng)驗(yàn)看來(lái),該版本的squid要比其他版本穩(wěn)定的多,以前的1.1.22版本也比較穩(wěn)定,但是在功能及靈活性方面有所欠缺。 
    squid有一個(gè)主要的配置文件squid.conf,在RedHat環(huán)境下所有squid的配置文件位于/etc/squid子目錄下。 

    4.1常用的配置選項(xiàng) 
    因?yàn)槿笔〉呐渲梦募袉栴},所以我們必須首先修改該配置文件的有關(guān)內(nèi)容,以便讓squid跑起來(lái)。 
    下面我們來(lái)看一看squid.conf文件的結(jié)構(gòu)以及一些常用的選項(xiàng): 
    squid.conf配置文件的可以分為十三個(gè)部分,這十三個(gè)部分分別是: 
    1.NETWORK OPTIONS (有關(guān)的網(wǎng)絡(luò)選項(xiàng)) 
    2.OPTIONS WHICH AFFECT THE NEIGHBOR SELECTION ALGORITHM (作用于鄰居選擇算 法的有關(guān)選項(xiàng)) 
    3.OPTIONS WHICH AFFECT THE CACHE SIZE (定義cache大小的有關(guān)選項(xiàng)) 
    4.LOGFILE PATHNAMES AND CACHE DIRECTORIES (定義日志文件的路徑及cache的目錄) 
    5.OPTIONS FOR EXTERNAL SUPPORT PROGRAMS (外部支持程序選項(xiàng)) 
    6.OPTIONS FOR TUNING THE CACHE (調(diào)整cache的選項(xiàng)) 
    7.TIMEOUTS (超時(shí)) 
    8.ACCESS CONTROLS (訪問控制) 
    9.ADMINISTRATIVE PARAMETERS (管理參數(shù)) 
    10.OPTIONS FOR THE CACHE REGISTRATION SERVICE (cache注冊(cè)服務(wù)選項(xiàng)) 
    11.HTTPD-ACCELERATOR OPTIONS (HTTPD加速選項(xiàng)) 
    12.MISCELLANEOUS (雜項(xiàng)) 
    13.DELAY POOL PARAMETERS (延時(shí)池參數(shù)) 
    雖然squid的配置文件很龐大,但是如果你只是為一個(gè)中小型網(wǎng)絡(luò)提供代理服務(wù),并且只準(zhǔn)備使用一臺(tái)服務(wù)器,那么,你只需要修改配置文件中的幾個(gè)選項(xiàng)。這些幾個(gè)常用選項(xiàng)分別是: 
    1.http_port 
    說(shuō)明:定義squid監(jiān)聽HTTP客戶連接請(qǐng)求的端口。缺省是3128,如果使用HTTPD加速模式 則為80。你可以指定多個(gè)端口,但是所有指定的端口都必須在一條命令行上。 
    2.cache_mem (bytes) 
    說(shuō)明:該選項(xiàng)用于指定squid可以使用的內(nèi)存的理想值。這部分內(nèi)存被用來(lái)存儲(chǔ)以下對(duì)象 : 
    In-Transit objects (傳入的對(duì)象) 
    Hot Objects (熱對(duì)象,即用戶常訪問的對(duì)象) 
    Negative-Cached objects (消極存儲(chǔ)的對(duì)象) 
    需要注意的是,這并沒有指明squid所使用的內(nèi)存一定不能超過該值,其實(shí),該選項(xiàng)只 定義了squid所使用的內(nèi)存的一個(gè)方面,squid還在其他方面使用內(nèi)存。所以squid實(shí)際 使用的內(nèi)存可能超過該值。缺省值為8MB。 
    3.cache_dir Directory-Name Mbytes Level-1 Level2 
    說(shuō)明:指定squid用來(lái)存儲(chǔ)對(duì)象的交換空間的大小及其目錄結(jié)構(gòu)。可以用多個(gè)cache_dir命令來(lái)定義多個(gè)這樣的交換空間,并且這些交換空間可以分布不同的磁盤分區(qū)。"directory "指明了該交換空間的頂級(jí)目錄。如果你想用整個(gè)磁盤來(lái)作為交換空間,那么你可以將該目錄作為裝載點(diǎn)將整個(gè)磁盤mount上去。缺省值為/var/spool/squid。“Mbytes”定義了可用的空間總量。需要注意的是,squid進(jìn)程必須擁有對(duì)該目錄的讀寫權(quán)力。“Level-1”是可以在該頂級(jí)目錄下建立的第一級(jí)子目錄的數(shù)目,缺省值為16。同理,“Level-2”是可以建立的第二級(jí)子目錄的數(shù)目,缺省值為256。為什么要定義這么多子目錄呢?這是因?yàn)槿绻幽夸浱伲瑒t存儲(chǔ)在一個(gè)子目錄下的文件數(shù)目將大大增加,這也會(huì)導(dǎo)致系統(tǒng)尋找某一個(gè)文件的時(shí)間大大增加,從而使系統(tǒng)的整體性能急劇降低。所以,為了減少每個(gè)目錄下的文件數(shù)量,我們必須增加所使用的目錄的數(shù)量。如果僅僅使用一級(jí)子目錄則頂級(jí)目錄下的子目錄數(shù)目太大了,所以我們使用兩級(jí)子目錄結(jié)構(gòu)。 
    那么,怎么來(lái)確定你的系統(tǒng)所需要的子目錄數(shù)目呢?我們可以用下面的公式來(lái)估算。 
    已知量: 
    DS = 可用交換空間總量(單位KB)/ 交換空間數(shù)目 
    OS = 平均每個(gè)對(duì)象的大小= 20k 
    NO = 平均每個(gè)二級(jí)子目錄所存儲(chǔ)的對(duì)象數(shù)目 = 256 
    未知量: 
    L1 = 一級(jí)子目錄的數(shù)量 
    L2 = 二級(jí)子目錄的數(shù)量 
    計(jì)算公式: 
    L1 x L2 = DS / OS / NO 
    注意這是個(gè)不定方程,可以有多個(gè)解。 
    4.acl 
    說(shuō)明:定義訪問控制列表。 
    定義語(yǔ)法為: 
    acl aclname acltype string1 ... 
    acl aclname acltype "file" ... 
    當(dāng)使用文件時(shí),該文件的格式為每行包含一個(gè)條目。 
    acltype 可以是 src dst srcdomain dstdomain url_pattern urlpath_pattern time port proto method browser user 中的一種。 
    分別說(shuō)明如下: 
    src 指明源地址。可以用以下的方法指定: 
    acl aclname src ip-address/netmask ... (客戶ip地址) 
    acl aclname src addr1-addr2/netmask ... (地址范圍) 
    dst 指明目標(biāo)地址。語(yǔ)法為: 
    acl aclname dst ip-address/netmask ... (即客戶請(qǐng)求的服務(wù)器的ip地址) 
    srcdomain 指明客戶所屬的域。語(yǔ)法為: 
    acl aclname srcdomain foo.com ... squid將根據(jù)客戶ip反向查詢DNS。 
    dstdomain 指明請(qǐng)求服務(wù)器所屬的域。語(yǔ)法為: 
    acl aclname dstdomain foo.com ... 由客戶請(qǐng)求的URL決定。 
    注意,如果用戶使用服務(wù)器ip而非完整的域名時(shí),squid將進(jìn)行反向的DNS解析來(lái)確 定其完整域名,如果失敗就記錄為“none”。 
    time 指明訪問時(shí)間。語(yǔ)法如下: 
    acl aclname time [day-abbrevs] [h1:m1-h2:m2][hh:mm-hh:mm] 
    day-abbrevs: 
    S - Sunday 
    M - Monday 
    T - Tuesday 
    W - Wednesday 
    H - Thursday 
    F - Friday 
    A - Saturday 
    h1:m1 必須小于 h2:m2,表達(dá)示為[hh:mm-hh:mm]。 
    port 指定訪問端口。可以指定多個(gè)端口,比如: 
    acl aclname port 80 70 21 ... 
    acl aclname port 0-1024 ... (指定一個(gè)端口范圍) 
    proto 指定使用協(xié)議。可以指定多個(gè)協(xié)議: 
    acl aclname proto HTTP FTP ... 
    method 指定請(qǐng)求方法。比如: 
    acl aclname method GET POST ... 
    5.http_access 
    說(shuō)明:根據(jù)訪問控制列表允許或禁止某一類用戶訪問。 
    如果某個(gè)訪問沒有相符合的項(xiàng)目,則缺省為應(yīng)用最后一條項(xiàng)目的“非”。比如最后一條為允許,則缺省就是禁止。所以,通常應(yīng)該把最后的條目設(shè)為"deny all" 或 "allow all" 來(lái)避免安全性隱患。
    4.2 應(yīng)用實(shí)例 
    假想情景:某公司用squid作代理服務(wù)器,該代理服務(wù)器配置為PII450/256M/8.4G,公司所用ip段為1.2.3.0/24,并且想用8080作為代理端口。 
    則相應(yīng)的squid配置選項(xiàng)為: 
    1.http_port 
    http_port 8080 
    2.cache_mem 
    思路:由于該服務(wù)器只提供代理服務(wù),所以該值可以盡量設(shè)得大一些。 
    cache_mem 194M 
    3.cache_dir Directory-Name Mbytes Level-1 Level2 
    思路:硬盤為8.4G的,在安裝系統(tǒng)時(shí)應(yīng)該做好規(guī)劃,為不同的文件系統(tǒng)劃分可用空間。在本例中,我們可以這樣來(lái)劃分: 
    /cache1 3.5G 
    /cache2 3.5G 
    /var 400M 
    swap 127M 
    / 剩余部分 
    并且,在安裝時(shí),我們盡量不安裝不必要的包。這樣在節(jié)約空間的同時(shí)可以提高系統(tǒng)的安全性和穩(wěn)定性。下面我們來(lái)計(jì)算所需的第一級(jí)和第二級(jí)子目錄數(shù)。 
    已知量: 
    DS = 可用交換空間總量(單位KB)/ 交換空間數(shù)目=7G/2=3500000KB 
    OS = 平均每個(gè)對(duì)象的大小= 20k 
    NO = 平均每個(gè)二級(jí)子目錄所存儲(chǔ)的對(duì)象數(shù)目 = 256 
    未知量: 
    L1 = 一級(jí)子目錄的數(shù)量 
    L2 = 二級(jí)子目錄的數(shù)量 
    計(jì)算公式: 
    L1 x L2 = DS / OS / NO=3500000/20/256=684 
    我們?nèi)?nbsp;
    L1=16 
    L2=43 
    所以,我們的cache_dir語(yǔ)句為: 
    cache_dir /cache1 3500M 16 43 
    cache_dir /cache2 3500M 16 43 
    4.acl 
    思路:通過src來(lái)定義acl. 
    acl allow_ip src 1.2.3.4/255.255.255.0 
    5.http_access 
    http_access allow allow_ip 

    4.3啟動(dòng)、停止squid。 
    配置并保存好squid.conf后,可以用以下命令啟動(dòng)squid。 
    squid 
    或者,使用RedHat的啟動(dòng)腳本來(lái)啟動(dòng)squid. 
    /etc/rc.d/init.d/squid start 
    同樣地,你也可以用下列腳本停止運(yùn)行squid或重啟動(dòng)squid. 
    /etc/rc.d/init.d/squid stop 
    /etc/rc.d/init.d/squid restart 

    五、根據(jù)需求配置你的squid——進(jìn)階篇 

    5.1其它配置選項(xiàng) 
    在進(jìn)行squid的一些高級(jí)應(yīng)用之前,我們有必要對(duì)其他有用的配置選項(xiàng)作一個(gè)全面的了解。下面我們分類來(lái)講一講這些選項(xiàng),用于某些特殊應(yīng)用的選項(xiàng)我們將放在講該種應(yīng)用時(shí)來(lái)講。 

    5.1.1網(wǎng)絡(luò)選項(xiàng) 
    1.tcp_incoming_address 
    tcp_outgoing_address 
    udp_incoming_address 
    udp_outgoing_address 
    說(shuō)明: 
    tcp_incoming_address指定監(jiān)聽來(lái)自客戶或其他squid代理服務(wù)器的綁定ip地址; 
    tcp_outgoing_address指定向遠(yuǎn)程服務(wù)器或其他squid代理服務(wù)器發(fā)起連接的ip地址 
    udp_incoming_address為ICP套接字指定接收來(lái)自其他squid代理服務(wù)器的包的ip地址 udp_outgoing_address為ICP套接字指定向其他squid代理服務(wù)器發(fā)送包的ip地址; 
    缺省為沒有綁定任何ip地址。該綁定地址可以用ip指定,也可以用完整的域名指定。 

    5.1.2交換空間設(shè)定選項(xiàng) 
    1.cache_swap_low (percent, 0-100) 
    cache_swap_high (percent, 0-100) 
    說(shuō)明:squid使用大量的交換空間來(lái)存儲(chǔ)對(duì)象。那么,過了一定的時(shí)間以后,該交換空間就會(huì)用完,所以還必須定期的按照某種指標(biāo)來(lái)將低于某個(gè)水平線的對(duì)象清除。squid使用所謂的“最近最少使用算法”(LRU)來(lái)做這一工作。當(dāng)已使用的交換空間達(dá)到cache_swap_high時(shí),squid就根據(jù)LRU所計(jì)算的得到每個(gè)對(duì)象的值將低于某個(gè)水平線的對(duì)象清除。這種清除工作一直進(jìn)行直到已用空間達(dá)到cache_swap_low。這兩個(gè)值用百分比表示,如果你所使用的交換空間很大的話,建議你減少這兩個(gè)值得差距,因?yàn)檫@時(shí)一個(gè)百分點(diǎn)就可能是幾百兆空間,這勢(shì)必影響squid的性能。缺省為: 
    cache_swap_low 90 
    cache_swap_high 95 
    2.maximum_object_size 
    說(shuō)明:大于該值得對(duì)象將不被存儲(chǔ)。如果你想要提高訪問速度,就請(qǐng)降低該值;如果你想最大限度地節(jié)約帶寬,降低成本,請(qǐng)?jiān)黾釉撝怠挝粸镵,缺省值為: 
    maximum_object_size 4096 KB 

    5.1.3有關(guān)日志的選項(xiàng) 
    1.cache_access_log 
    說(shuō)明:指定客戶請(qǐng)求記錄日志的完整路徑(包括文件的名稱及所在的目錄),該請(qǐng)求可以是來(lái)自一般用戶的HTTP請(qǐng)求或來(lái)自鄰居的ICP請(qǐng)求。缺省值為: 
    cache_access_log /var/log/squid/access.log 
    如果你不需要該日志,可以用以下語(yǔ)句取消:cache_access_log none 
    2.cache_store_log 
    說(shuō)明:指定對(duì)象存儲(chǔ)記錄日志的完整路徑(包括文件的名稱及所在的目錄)。該記錄表明哪些對(duì)象被寫到交換空間,哪些對(duì)象被從交換空間清除。缺省路徑為: 
    cache_log /var/log/squid/cache.log 
    如果你不需要該日志,可以用以下語(yǔ)句取消:cache_store_log none 
    3.cache_log 
    說(shuō)明:指定squid一般信息日志的完整路徑(包括文件的名稱及所在的目錄)。 
    缺省路徑為:cache_log /var/log/squid/cache.log 
    4.cache_swap_log 
    說(shuō)明:該選項(xiàng)指明每個(gè)交換空間的“swap.log”日志的完整路徑(包括文件的名稱及所在的目錄)。該日志文件包含了存儲(chǔ)在交換空間里的對(duì)象的元數(shù)據(jù)(metadata)。通常,系統(tǒng)將該文件自動(dòng)保存在第一個(gè)“cache_dir”說(shuō)定義的頂級(jí)目錄里,但是你也可以指定其他的路徑。如果你定義了多個(gè)“cache_dir”,則相應(yīng)的日志文件可能是這樣的: 
    cache_swap_log.00 
    cache_swap_log.01 
    cache_swap_log.02 
    后面的數(shù)字?jǐn)U展名與指定的多個(gè)“cache_dir”一一對(duì)應(yīng)。 
    需要注意的是,最好不要?jiǎng)h除這類日志文件,否則squid將不能正常工作。 
    5.pid_filename 
    說(shuō)明:指定記錄squid進(jìn)程號(hào)的日志的完整路徑(包括文件的名稱及所在的目錄)。缺省路徑為 
    pid_filename /var/run/squid.pid 
    如果你不需要該文件,可以用以下語(yǔ)句取消:pid_filename none 
    6.debug_options 
    說(shuō)明:控制作日志時(shí)記錄信息的多寡。可以從兩個(gè)方面控制:section控制從幾個(gè)方面作記錄;level控制每個(gè)方面的記錄的詳細(xì)程度。推薦的方式(也是缺省方式)是:debug_options ALL,1 
    即,對(duì)每個(gè)方面都作記錄,但詳細(xì)程度為1(最低)。 
    7.log_fqdn on|off 
    說(shuō)明:控制在 access.log 中對(duì)用戶地址的記錄方式。打開該選項(xiàng)時(shí),squid記錄客戶的完整域名,取消該選項(xiàng)時(shí),squid記錄客戶的ip地址。注意,如果打開該選項(xiàng)會(huì)增加系統(tǒng)的負(fù)擔(dān),因?yàn)閟quid還得進(jìn)行客戶ip的DNS查詢。缺省值為:log_fqdn off 

    5.1.4有關(guān)外部支持程序的選項(xiàng) 
    1.ftp_user 
    說(shuō)明:設(shè)置登錄匿名ftp服務(wù)器時(shí)的提供的電子郵件地址,登錄匿名ftp服務(wù)器時(shí)要求用你的電子郵件地址作為登錄口令(更多的信息請(qǐng)參看本書的相關(guān)章節(jié))。需要注意的是,有的匿名ftp服務(wù)器對(duì)這一點(diǎn)要求很苛刻,有的甚至?xí)z查你的電子郵件的有效性。缺省值為:ftp_user Squid@ 
    2.ftp_list_width 
    說(shuō)明:設(shè)置ftp列表的寬度,如果設(shè)得太小將不能的瀏覽到長(zhǎng)文件名。缺省值為: ftp_list_width 32 
    3.cache_dns_program 
    說(shuō)明:指定DNS查詢程序的完整路徑(包括文件的名稱及所在的目錄)。缺省路徑為: 
    cache_dns_program /usr/lib/squid/dnsserver 
    4.dns_children 
    說(shuō)明:設(shè)置DNS查詢程序的進(jìn)程數(shù)。對(duì)于大型的登錄服務(wù)器系統(tǒng),建議該值至少為10。最大值可以是32,缺省設(shè)置為5個(gè)。注意,如果你任意的降低該值,可能會(huì)使系統(tǒng)性能急劇降低,因?yàn)閟quid主進(jìn)程要等待域名查詢的結(jié)果。沒有必要減少該值,因?yàn)镈NS查詢進(jìn)程并不會(huì)消耗太多的系統(tǒng)的資源。 
    5.dns_nameservers 
    說(shuō)明:指定一個(gè)DNS服務(wù)器列表,強(qiáng)制squid使用該列表中的DNS服務(wù)器而非使用/etc/resolv.conf文件中定義的DNS服務(wù)器。你可以這樣指定多個(gè)DNS服務(wù)器:dns_nameservers 10.0.0.1 192.172.0.4 
    缺省設(shè)置為:dns_nameservers none 
    6.unlinkd_program 
    說(shuō)明:指定文件刪除進(jìn)程的完整路徑。 
    缺省設(shè)置為: 
    unlinkd_program /usr/lib/squid/unlinkd 
    7.pinger_program 
    說(shuō)明:指定ping進(jìn)程的完整路徑。該進(jìn)程被squid利用來(lái)測(cè)量與其他鄰居的路由距離。該選項(xiàng)只在你啟用了該功能時(shí)有用。缺省為: 
    pinger_program /usr/lib/squid/pinger 
    8.authenticate_program 
    說(shuō)明:指定用來(lái)進(jìn)行用戶認(rèn)證的外部程序的完整路徑。squid的用戶認(rèn)證功能我們將在后面的章節(jié)講述。缺省設(shè)置為不認(rèn)證。 

    5.1.5用戶訪問控制選項(xiàng) 
    1.request_size (KB) 
    說(shuō)明:設(shè)置用戶請(qǐng)求通訊量的最大允許值(單位為KB)。如果用戶用POST方法請(qǐng)求時(shí),應(yīng)該設(shè)一個(gè)較大的值。缺省設(shè)置為: 
    request_size 100 KB 
    2.reference_age 
    說(shuō)明:squid根據(jù)對(duì)象的LRU(最近最少使用算法)來(lái)清除對(duì)象,squid依據(jù)使用磁盤空間的總量動(dòng)態(tài)地計(jì)算對(duì)象的LRU年齡。我們用reference_age定義對(duì)象的最大LRU年齡。如果一個(gè)對(duì)象在指定的reference_age內(nèi)沒有被訪問,squid將刪除該對(duì)象。缺省值為一個(gè)月。你可以使用如下所示的時(shí)間表示方法。 
    1 week 
    3.5 days 
    4 months 
    2.2 hours 
    3.quick_abort_min (KB) 
    quick_abort_max (KB) 
    quick_abort_pct (percent) 
    說(shuō)明:控制squid是否繼續(xù)傳輸被用戶中斷的請(qǐng)求。當(dāng)用戶中斷請(qǐng)求時(shí),squid將檢測(cè) 
    quick_abort 的值。如果剩余部分小于“quick_abort_min”指定的值,squid 將繼續(xù)完成剩余部分的傳輸;如果剩余部分大于“quick_abort_max”指定的值,squid 將終止剩余部分的傳輸;如果已完成“quick_abort_pct”指定的百分比,squid將繼續(xù)完成剩余部分的傳輸。缺省的設(shè)置為: 
    quick_abort_min 16 KB 
    quick_abort_max 16 KB 
    quick_abort_pct 95 

    5.1.6各類超時(shí)設(shè)置選項(xiàng) 
    1.negative_ttl time-units 
    說(shuō)明:設(shè)置消極存儲(chǔ)對(duì)象的生存時(shí)間。所謂的消極存儲(chǔ)對(duì)象,就是諸如“連接失敗”及"404 Not Found"等一類錯(cuò)誤信息。缺省設(shè)置為:negative_ttl 5 minutes 
    2.positive_dns_ttl time-units 
    說(shuō)明:設(shè)置緩存成功的DNS查詢結(jié)果的生存時(shí)間。缺省為6小時(shí)。 
    positive_dns_ttl 6 hours 
    3.negative_dns_ttl time-units 
    說(shuō)明:設(shè)置緩存失敗的DNS查詢結(jié)果的生存時(shí)間。缺省為5分鐘。 
    negative_dns_ttl 5 minutes 
    4.connect_timeout time-units 
    說(shuō)明:設(shè)置squid等待連接完成的超時(shí)值。缺省值為2分鐘。 
    connect_timeout 120 seconds 
    5.read_timeout time-units 
    說(shuō)明:如果在指定的時(shí)間內(nèi)squid尚未從被請(qǐng)求的服務(wù)器讀入任何數(shù)據(jù),則squid將終止該客戶請(qǐng)求。缺省值為15分鐘。 
    read_timeout 15 minutes 
    6.request_timeout 
    說(shuō)明:設(shè)置在建立與客戶的連接后,squid將花多長(zhǎng)時(shí)間等待客戶發(fā)出HTTP請(qǐng)求。缺省值為30秒。 
    request_timeout 30 seconds 
    7.client_lifetime time-units 
    說(shuō)明:設(shè)置客戶在與squid建立連接后,可以將該連接保持多長(zhǎng)時(shí)間。 
    注意,因?yàn)榭蛻艚⒌拿總€(gè)連接都會(huì)消耗一定的系統(tǒng)資源,所以如果你是為一個(gè)大型網(wǎng)絡(luò)提供代理服務(wù)的話,一定要正確地修改該值。因?yàn)槿绻粫r(shí)間的連接數(shù)量太大的話,可能會(huì)消耗大量的系統(tǒng)資源,從而導(dǎo)致服務(wù)器宕機(jī)。缺省值為1天,該值太大了,建議根據(jù)你自己的情況適當(dāng)減小該值。 
    client_lifetime 1 day 
    8.half_closed_clients on/off 
    說(shuō)明:有時(shí)候由于用戶的不正常操作,可能會(huì)使與squid的TCP連接處于半關(guān)閉狀態(tài), 
    這時(shí)候,該TCP連接的發(fā)送端已經(jīng)關(guān)閉,而接收端正常工作。缺省地,squid將一直保持這種處于半關(guān)閉狀態(tài)的TCP連接,直到返回套接字的讀寫錯(cuò)誤才將其關(guān)閉。如果將該值設(shè)為off,則一旦從客戶端返回“no more data to read”的信息,squid就立即關(guān)閉該連接。half_closed_clients on 
    9.pconn_timeout 
    說(shuō)明:設(shè)置squid在與其他服務(wù)器和代理建立連接后,該連接閑置多長(zhǎng)時(shí)間后被關(guān)閉。缺省值為120秒。 
    pconn_timeout 120 seconds 
    10.ident_timeout 
    說(shuō)明:設(shè)置squid等待用戶認(rèn)證請(qǐng)求的時(shí)間。缺省值為10秒。 
    ident_timeout 10 seconds 
    11.shutdown_lifetime time-units 
    說(shuō)明:當(dāng)收到SIGTERM 或者 SIGHUP 信號(hào)后, squid將進(jìn)入一種shutdown pending的模式,等待所有活動(dòng)的套接字關(guān)閉。在過了shutdown_lifetime所定義的時(shí)間后,所有活動(dòng)的用戶都將收到一個(gè)超時(shí)信息。缺省值為30秒。 
    shutdown_lifetime 30 seconds 

    5.1.7管理參數(shù)選項(xiàng) 
    1.cache_mgr 
    說(shuō)明:設(shè)置管理員郵件地址。缺省為: 
    cache_mgr root 
    2. cache_effective_user 
    cache_effective_group 
    說(shuō)明:如果用root啟動(dòng)squid,squid將變成這兩條語(yǔ)句指定的用戶和用戶組。缺省變?yōu)閟quid用戶和squid用戶組。注意這里指定的用戶和用戶組必須真是存在于/etc/passwd中。如果用非root帳號(hào)啟動(dòng)squid,則squid將保持改用戶及用戶組運(yùn)行,這時(shí)候,你不能指定小于1024地http_port。 
    cache_effective_user squid 
    cache_effective_group squid 
    3.visible_hostname 
    說(shuō)明:定義在返回給用戶的出錯(cuò)信息中的主機(jī)名。 
    如: visible_hostname www-cache.foo.org 
    4.unique_hostname 
    說(shuō)明:如果你有一個(gè)代理服務(wù)器陣列,并且你為每個(gè)代理服務(wù)器指定了同樣的“visible_hostname”,同時(shí)你必須為它們指定不同的“unique_hostname”來(lái)避免“forwarding loops ”(傳輸循環(huán))發(fā)生。 

    5.1.8其它雜項(xiàng) 
    1. dns_testnames 
    說(shuō)明:設(shè)置進(jìn)行DNS查詢測(cè)試,如果第一個(gè)站點(diǎn)解析成功則立即結(jié)束DNS查詢測(cè)試。如果你不愿意進(jìn)行DNS查詢測(cè)試,就不要去掉缺省的設(shè)置。 
    #dns_testnames netscape.com internic.net nlanr.net microsoft.com 
    2.logfile_rotate 
    說(shuō)明:通常,squid會(huì)定期的將日志文件更名并打包。比如正在使用的日志文件為access.log,squid會(huì)將其更名并打包為access.log.1.gz;過了一定時(shí)間后,squid又會(huì)將 
    access.log.1.gz更名為access.log.2.gz并將當(dāng)前的日志文件更名并打包為access.log.1.gz,以此循環(huán)。logfile_rotate所指定的數(shù)字即為打包并備份的文件的數(shù)量,當(dāng)達(dá)到這一數(shù)目時(shí),squid將刪除最老的備份文件。缺省值為10。如果你想手動(dòng)來(lái)進(jìn)行這些操作,你可以用logfile_rotate 0來(lái)取消自動(dòng)操作。 
    3.err_html_text 
    說(shuō)明:用該語(yǔ)句定義一個(gè)字符串變量,可以用%L在返回給用戶的錯(cuò)誤信息文件中引用。錯(cuò)誤信息文件通常在/etc/squid/errors目錄中,這是一些用HTML寫成的腳本文件,你可以自己修改它。 
    4.deny_info 
    說(shuō)明:你可以定制自定義的拒絕訪問信息文件,并且可以和不同的用戶列表相關(guān)聯(lián)。當(dāng)用戶被http_access相關(guān)規(guī)則拒絕時(shí),squid可以向用戶顯示你自定義的相應(yīng)的拒絕訪問信息文件。語(yǔ)法為: 
    Usage: deny_info err_page_name acl 
    比如: 
    deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys 
    5.memory_pools on|off 
    說(shuō)明:如果你將該項(xiàng)設(shè)為on,則squid將保留所有已經(jīng)分配(但是未使用)的內(nèi)存池以便在將來(lái)使用。缺省為on. 
    memory_pools on 
    6.log_icp_queries on|off 
    說(shuō)明:設(shè)置是否對(duì)ICP請(qǐng)求作日志。如果你的系統(tǒng)負(fù)載很大,你可以用off來(lái)取消該功能。缺省為: 
    log_icp_queries on 
    7.always_direct 
    說(shuō)明:該選項(xiàng)允許你指定某些用戶類,squid將這些用戶類的請(qǐng)求直接轉(zhuǎn)發(fā)給被請(qǐng)求的服務(wù)器。語(yǔ)法為: 
    always_direct allow|deny [!]aclname ... 
    如:直接轉(zhuǎn)發(fā)FTP請(qǐng)求可以這樣設(shè)置: 
    acl FTP proto FTP 
    always_direct allow FTP 
    8.never_direct 
    說(shuō)明:與always_direct相反。語(yǔ)法為: 
    Usage: never_direct allow|deny [!]aclname ... 
    比如,為了強(qiáng)制除了本地域的其他用戶使用代理服務(wù)器,你可以這樣設(shè)置: 
    acl local-servers dstdomain foo.net 
    acl all src 0.0.0.0/0.0.0.0 
    never_direct deny local-servers 
    never_direct allow all 
    9.icon_directory 
    說(shuō)明:指明向用戶傳送錯(cuò)誤信息時(shí)所用到的圖標(biāo)文件的目錄。缺省路徑為: icon_directory /usr/lib/squid/icons 
    10.error_directory 
    說(shuō)明:指明向用戶傳送錯(cuò)誤信息所用到的錯(cuò)誤描述文件的目錄。缺省路徑為: 
    error_directory /etc/squid/errors 

    5.2 用戶認(rèn)證設(shè)置 
    缺省的,squid本身不帶任何認(rèn)證程序,但是我們可以通過外部認(rèn)證程序來(lái)實(shí)現(xiàn)用戶認(rèn)證。一般說(shuō)來(lái)有以下的認(rèn)證程序: 
    1.LDAP認(rèn)證:你可以訪問以下資源來(lái)獲取更多的有用信息。 
    http://www.geocities.com/ResearchTriangle/Thinktank/5292/projects/ldap/ 
    http://home.iae.nl/users/devet/squid/proxy_auth/contrib/ldap_auth.tar.gz 
    2.SMB認(rèn)證:可以實(shí)現(xiàn)基于NT和samba的用戶認(rèn)證。更多的信息請(qǐng)?jiān)L問以下資源。 
    http://www.hacom.nl/~richard/software/smb_auth.html 
    3.基于mysql的用戶認(rèn)證。 
    http://home.iae.nl/users/devet/squid/proxy_auth/contrib/mysql_auth.c 
    4.基于sock5密碼用戶認(rèn)證。 
    http://nucleo.freeservers.com/ 
    5.基于Radius 的用戶認(rèn)證。 
    http://home.iae.nl/users/devet/squid/proxy_auth/contrib/auth.pl 
    但是我們一般常用的是用ncsa實(shí)現(xiàn)的認(rèn)證和用smb_auth實(shí)現(xiàn)的基于NT和samba的用戶認(rèn)證。下面我們就來(lái)講這兩種認(rèn)證方法的具體實(shí)現(xiàn)。 

    5.2.1 ncsa用戶認(rèn)證的實(shí)現(xiàn) 
    ncsa是squid源代碼包自帶的認(rèn)證程序之一,下面我們以squid-2.3.STABLE2版本為例講述ncsa的安裝和配置。 
    1.從www.squid-cache.org下載squid源代碼包squid-2.3.STABLE2-src.tar.gz并放到/tmp目錄下。 
    2.用tar解開: 
    tar xvzf squid-2.3.STABLE2-src.tar.gz 
    %make 
    %make install 
    3.然后,進(jìn)入/tmp/squid-2.3.STABLE2/auth_modules/NCSA目錄。 
    % make 
    % make install 
    編譯成功后,會(huì)生成ncsa_auth的可執(zhí)行文件。 
    4.拷貝生成的執(zhí)行文件ncsa_auth到/usr/bin目錄 
    cp ncsa_auth /usr/bin/bin 
    5.修改squid.conf中的相關(guān)選項(xiàng)如下所示: 
    authenticate_program /usr/local/squid/bin/ncsa_auth /usr/bin/passwd 
    6.定義相關(guān)的用戶類 
    acl auth_user proxy_auth REQUIRED 
    注意,REQUIRED關(guān)鍵字指明了接收所有合法用戶的訪問。 
    7.設(shè)置http_access 
    http_access allow auth_user 
    注意,如果你在改行中指定了多個(gè)允許訪問的用戶類的話,應(yīng)該把要認(rèn)證的用戶類放在第一個(gè)。如下所示: 
    錯(cuò)誤的配置:http_access allow auth_user all manager 
    正確的配置:http_access allow auth_user manager all 
    8.利用apache攜帶的工具軟件htpasswd在/usr/local/squid/etc下生成密碼文件并添加相應(yīng)的用戶信息。一般說(shuō)來(lái),該密碼文件每行包含一個(gè)用戶的用戶信息,即用戶名和密碼。 
    用htpasswd生成密碼文件passwd并添加用戶bye。 
    htpasswd -c /usr/local/squid/etc/passwd bye 
    然后重新啟動(dòng)squid,密碼認(rèn)證已經(jīng)生效。 

    5.2.2 smb用戶認(rèn)證的實(shí)現(xiàn) 
    國(guó)內(nèi)介紹并使用ncsa實(shí)現(xiàn)用戶認(rèn)證的文章不多,而使用smb_auth和samba實(shí)現(xiàn)基于NT的用戶認(rèn)證我還沒有看到過,下面我們就來(lái)看一看在squid中實(shí)現(xiàn)基于NT的用戶認(rèn)證。 
    當(dāng)前smb_auth的最高版本是smb_auth-0.05,你可以在以下地址下載。當(dāng)然,squid的源代碼包中也包含smb_auth,但是是0.02版的。 
    http://www.hacom.nl/~richard/software/smb_auth-0.05.tar.gz 
    smb_auth的主頁(yè)地址是http://www.hacom.nl/~richard/software/smb_auth.html。 
    1.系統(tǒng)需求: 
    squid2.0以上版本。 
    安裝samba2.0.4以上版本。你并不需要運(yùn)行samba服務(wù),因?yàn)閟mb_auth只用到了 samba的客戶端軟件。 
    2.下載smb_auth-0.05.tar.gz并復(fù)制到/tmp. 
    3.tar xvzf smb_auth-0.05.tar.gz 
    4.根據(jù)你的要求修改Makefile中的SAMBAPREFIX和INSTALLBIN參數(shù)。SAMBAPREFIX指定了你的samba安裝路徑,INSTALLBIN指明了smb_auth的安裝路徑。我們指定: 
    SAMBAPREFIX=/usr,INSTALLBIN=/usr/bin. 
    5.make 
    6.make install,成功后會(huì)在INSTALLBIN指定路徑中生成可執(zhí)行文件smb_auth. 
    7.按下列步驟設(shè)置你要用于認(rèn)證的主域控制器: 
    首先在NETLOG共享目錄中建立一個(gè)“proxy”文件,該文件只包含一個(gè)“allow”的字符串,一般說(shuō)來(lái),該NETLOG目錄位于winntsystem32Replimportscripts目錄中;然后,設(shè)置所有你想讓其訪問squid的用戶和用戶組擁有對(duì)該文件的讀的權(quán)力。 
    8.修改squid.conf中的相關(guān)選項(xiàng)如下所示: 
    authenticate_program /usr/local/squid/bin/smb_auth your_domain_name 
    9.定義相關(guān)的用戶類 
    acl auth_user proxy_auth REQUIRED 
    注意,REQUIRED關(guān)鍵字指明了接收所有合法用戶的訪問。 
    10.設(shè)置http_access 
    http_access allow auth_user 
    注意,如果你在改行中指定了多個(gè)允許訪問的用戶類的話,應(yīng)該把要認(rèn)證的用戶類放在第一個(gè)。如下所示: 
    錯(cuò)誤的配置:http_access allow auth_user all manager 
    正確的配置:http_access allow auth_user manager all 
    如果一切正確的話,然后重新啟動(dòng)squid,密碼認(rèn)證已經(jīng)生效。 
    說(shuō)明:smb_auth的調(diào)用方法: 
    1.smb_auth -W your_domain_name 
    用your_domain_name指定你的域名。smb_auth將進(jìn)行廣播尋找該主域控制器。 
    2.smb_auth -W your_domain_name -B 
    如果你有多個(gè)網(wǎng)絡(luò)接口,可以用-B 指定用于廣播的網(wǎng)絡(luò)接口的ip地址。 
    3.smb_auth -W your_domain_name -U 
    也可以用-U直接指定該主域控制器的ip地址。 
    4.smb_auth -W your_domain_name -S share 
    可以用-S指定一個(gè)不同于NETLOG的共享目錄。 

    5.2.3 squid.conf中關(guān)于認(rèn)證的其他設(shè)置 
    1.authenticate_children 
    說(shuō)明:設(shè)置認(rèn)證子進(jìn)程的數(shù)目。缺省為5個(gè)。如果你處于一個(gè)繁忙的網(wǎng)絡(luò)環(huán)境中,你可以適當(dāng)增大該值。 
    2.authenticate_ttl 
    說(shuō)明:設(shè)置一次認(rèn)證的有效期,缺省是3600秒。 
    3.proxy_auth_realm 
    說(shuō)明:設(shè)置用戶登錄認(rèn)證時(shí)向用戶顯示的域名。 

    5.3透明代理的設(shè)置 
    關(guān)于透明代理的概念我們已經(jīng)在第一節(jié)將過了,下面我們看一下怎么樣在squid中實(shí)現(xiàn)透明代理。 
    透明代理的實(shí)現(xiàn)需要在Linux 2.0.29以上,但是Linux 2.0.30并不支持該功能,好在我們現(xiàn)在使用的通常是2.2.X以上的版本,所以不必?fù)?dān)心這個(gè)問題。下面我們就用ipchains+squid來(lái)實(shí)現(xiàn)透明代理。在開始之前需要說(shuō)明的是,目前我們只能實(shí)現(xiàn)支持HTTP的透明代理,但是也不必太擔(dān)心,因?yàn)槲覀冎允褂么恚康氖抢胹quid的緩存來(lái)提高Web的訪問速度,至于提供內(nèi)部非法ip地址的訪問及提高網(wǎng)絡(luò)安全性,我們可以用ipchains來(lái)解決。 
    實(shí)現(xiàn)環(huán)境:RedHat6.x+squid2.2.x+ipchains 

    5.3.1 linux的相關(guān)配置 
    確定你的內(nèi)核已經(jīng)配置了以下特性: 
    [*] Network firewalls 
    [ ] Socket Filtering 
    [*] Unix domain sockets 
    [*] TCP/IP networking 
    [ ] IP: multicasting 
    [ ] IP: advanced router 
    [ ] IP: kernel level autoconfiguration 
    [*] IP: firewalling 
    [ ] IP: firewall packet netlink device 
    [*] IP: always defragment (required for masquerading) 
    [*] IP: transparent proxy support 
    如果沒有,請(qǐng)你重新編譯內(nèi)核。一般在RedHat6.x以上,系統(tǒng)已經(jīng)缺省配置了這些特性。 

    5.3.2squid的相關(guān)配置選項(xiàng) 
    設(shè)置squid.conf中的相關(guān)選項(xiàng),如下所示: 
    http_port 3218 
    httpd_accel_host virtual 
    httpd_accel_port 80 
    httpd_accel_with_proxy on 
    httpd_accel_uses_host_header on 
    說(shuō)明: 
    1.http_port 3128 
    在本例中,我們假設(shè)squid的HTTP監(jiān)聽端口為3128,即squid缺省設(shè)置值。然后,把所有來(lái)自于客戶端web請(qǐng)求的包(即目標(biāo)端口為80)重定向到3128端口。 
    2.httpd_accel_host virtual 
    httpd_accel_port 80 
    這兩個(gè)選項(xiàng)本來(lái)是用來(lái)定義squid加速模式的。在這里我們用virtual來(lái)指定為虛擬主機(jī)模式。80端口為要加速的請(qǐng)求端口。采用這種模式時(shí),squid就取消了緩存及ICP功能,假如你需要這些功能,這必須設(shè)置httpd_accel_with_proxy選項(xiàng)。 
    3.httpd_accel_with_proxy on 
    該選項(xiàng)在透明代理模式下是必須設(shè)置成on的。在該模式下,squid既是web請(qǐng)求的加速器,又是緩存代理服務(wù)器。 
    4.httpd_accel_uses_host_header on 
    在透明代理模式下,如果你想讓你代理服務(wù)器的緩存功能正確工作的話,你必須將該選項(xiàng)設(shè)為on。設(shè)為on時(shí),squid會(huì)把存儲(chǔ)的對(duì)象加上主機(jī)名而不是ip地址作為索引。這一點(diǎn)在你想建立代理服務(wù)器陣列時(shí)顯得尤為重要。 

    5.3.3 ipchains的相關(guān)配置 
    ipchains在這里所起的作用是端口重定向。我們可以使用下列語(yǔ)句實(shí)現(xiàn)將目標(biāo)端口為80端口的TCP包重定向到3128端口。 
    #接收所有的回送包 
    /sbin/ipchains -A input -j ACCEPT -i lo 
    #將目標(biāo)端口為80端口的TCP包重定向到3128端口 
    /sbin/ipchains -A input -p tcp -d 0.0.0.0/0 80 -j REDIRECT 80 
    當(dāng)然在這以前,我們必須用下面的語(yǔ)句打開包轉(zhuǎn)發(fā)功能。 
    echo 1 > /proc/sys/net/ipv4/ip_forward 

    小節(jié) 
    開始,我們討論了代理服務(wù)器的概念,代理服務(wù)器的分類;然后,我們把注意力集中在squid,講述了如何安裝和配置squid;最后我們講了一些squid配置中的高級(jí)話題,即實(shí)現(xiàn)用戶認(rèn)證的兩種方法,透明代理的實(shí)現(xiàn)等。當(dāng)然,還有一些高級(jí)話題本章沒有講到,如代理陣列的實(shí)現(xiàn),加速模式的運(yùn)用等等。但是,我們不可能把所有東西都講完講全,希望讀者能舉一反三,自己去摸索,去嘗試。
    posted @ 2009-03-02 17:53 小馬歌 閱讀(297) | 評(píng)論 (0)編輯 收藏
     
    摘要 內(nèi)存管理對(duì)于長(zhǎng)期運(yùn)行的程序,例如服務(wù)器守護(hù)程序,是相當(dāng)重要的影響;因此,理解PHP是如何分配與釋放內(nèi)存的對(duì)于創(chuàng)建這類程序極為重要。本文將重點(diǎn)探討PHP的內(nèi)存管理問題。

      一、 內(nèi)存

      在PHP中,填充一個(gè)字符串變量相當(dāng)簡(jiǎn)單,這只需要一個(gè)語(yǔ)句"<?php $str = 'hello world '; ?>"即可,并且該字符串能夠被自由地修改、拷貝和移動(dòng)。而在C語(yǔ)言中,盡管你能夠編寫例如"char *str = "hello world ";"這樣的一個(gè)簡(jiǎn)單的靜態(tài)字符串;但是,卻不能修改該字符串,因?yàn)樗嬗诔绦蚩臻g內(nèi)。為了創(chuàng)建一個(gè)可操縱的字符串,你必須分配一個(gè)內(nèi)存塊,并且通過一個(gè)函數(shù)(例如strdup())來(lái)復(fù)制其內(nèi)容。

    {
     char *str;
     str = strdup("hello world");
     if (!str) {
      fprintf(stderr, "Unable to allocate memory!");
     }
    }

      由于后面我們將分析的各種原因,傳統(tǒng)型內(nèi)存管理函數(shù)(例如malloc(),free(),strdup(),realloc(),calloc(),等等)幾乎都不能直接為PHP源代碼所使用。

      二、 釋放內(nèi)存

      在幾乎所有的平臺(tái)上,內(nèi)存管理都是通過一種請(qǐng)求和釋放模式實(shí)現(xiàn)的。首先,一個(gè)應(yīng)用程序請(qǐng)求它下面的層(通常指"操作系統(tǒng)"):"我想使用一些內(nèi)存空間"。如果存在可用的空間,操作系統(tǒng)就會(huì)把它提供給該程序并且打上一個(gè)標(biāo)記以便不會(huì)再把這部分內(nèi)存分配給其它程序。
    當(dāng)應(yīng)用程序使用完這部分內(nèi)存,它應(yīng)該被返回到OS;這樣以來(lái),它就能夠被繼續(xù)分配給其它程序。如果該程序不返回這部分內(nèi)存,那么OS無(wú)法知道是否這塊內(nèi)存不再使用并進(jìn)而再分配給另一個(gè)進(jìn)程。如果一個(gè)內(nèi)存塊沒有釋放,并且所有者應(yīng)用程序丟失了它,那么,我們就說(shuō)此應(yīng)用程序"存在漏洞",因?yàn)檫@部分內(nèi)存無(wú)法再為其它程序可用。

      在一個(gè)典型的客戶端應(yīng)用程序中,較小的不太經(jīng)常的內(nèi)存泄漏有時(shí)能夠?yàn)镺S所"容忍",因?yàn)樵谶@個(gè)進(jìn)程稍后結(jié)束時(shí)該泄漏內(nèi)存會(huì)被隱式返回到OS。這并沒有什么,因?yàn)镺S知道它把該內(nèi)存分配給了哪個(gè)程序,并且它能夠確信當(dāng)該程序終止時(shí)不再需要該內(nèi)存。

      而對(duì)于長(zhǎng)時(shí)間運(yùn)行的服務(wù)器守護(hù)程序,包括象Apache這樣的web服務(wù)器和擴(kuò)展php模塊來(lái)說(shuō),進(jìn)程往往被設(shè)計(jì)為相當(dāng)長(zhǎng)時(shí)間一直運(yùn)行。因?yàn)镺S不能清理內(nèi)存使用,所以,任何程序的泄漏-無(wú)論是多么小-都將導(dǎo)致重復(fù)操作并最終耗盡所有的系統(tǒng)資源。

      現(xiàn)在,我們不妨考慮用戶空間內(nèi)的stristr()函數(shù);為了使用大小寫不敏感的搜索來(lái)查找一個(gè)字符串,它實(shí)際上創(chuàng)建了兩個(gè)串的各自的一個(gè)小型副本,然后執(zhí)行一個(gè)更傳統(tǒng)型的大小寫敏感的搜索來(lái)查找相對(duì)的偏移量。然而,在定位該字符串的偏移量之后,它不再使用這些小寫版本的字符串。如果它不釋放這些副本,那么,每一個(gè)使用stristr()的腳本在每次調(diào)用它時(shí)都將泄漏一些內(nèi)存。最后,web服務(wù)器進(jìn)程將擁有所有的系統(tǒng)內(nèi)存,但卻不能夠使用它。

      你可以理直氣壯地說(shuō),理想的解決方案就是編寫良好、干凈的、一致的代碼。這當(dāng)然不錯(cuò);但是,在一個(gè)象PHP解釋器這樣的環(huán)境中,這種觀點(diǎn)僅對(duì)了一半。

      三、 錯(cuò)誤處理

      為了實(shí)現(xiàn)"跳出"對(duì)用戶空間腳本及其依賴的擴(kuò)展函數(shù)的一個(gè)活動(dòng)請(qǐng)求,需要使用一種方法來(lái)完全"跳出"一個(gè)活動(dòng)請(qǐng)求。這是在Zend引擎內(nèi)實(shí)現(xiàn)的:在一個(gè)請(qǐng)求的開始設(shè)置一個(gè)"跳出"地址,然后在任何die()或exit()調(diào)用或在遇到任何關(guān)鍵錯(cuò)誤(E_ERROR)時(shí)執(zhí)行一個(gè)longjmp()以跳轉(zhuǎn)到該"跳出"地址。

      盡管這個(gè)"跳出"進(jìn)程能夠簡(jiǎn)化程序執(zhí)行的流程,但是,在絕大多數(shù)情況下,這會(huì)意味著將會(huì)跳過資源清除代碼部分(例如free()調(diào)用)并最終導(dǎo)致出現(xiàn)內(nèi)存漏洞。現(xiàn)在,讓我們來(lái)考慮下面這個(gè)簡(jiǎn)化版本的處理函數(shù)調(diào)用的引擎代碼:

    void call_function(const char *fname, int fname_len TSRMLS_DC){
     zend_function *fe;
     char *lcase_fname;
     /* PHP函數(shù)名是大小寫不敏感的,
     *為了簡(jiǎn)化在函數(shù)表中對(duì)它們的定位,
     *所有函數(shù)名都隱含地翻譯為小寫的
     */
     lcase_fname = estrndup(fname, fname_len);
     zend_str_tolower(lcase_fname, fname_len);
     if (zend_hash_find(EG(function_table),lcase_fname, fname_len + 1, (void **)&fe) == FAILURE) {
      zend_execute(fe->op_array TSRMLS_CC);
     } else {
      php_error_docref(NULL TSRMLS_CC, E_ERROR,"Call to undefined function: %s()", fname);
     }
     efree(lcase_fname);
    }

      當(dāng)執(zhí)行到php_error_docref()這一行時(shí),內(nèi)部錯(cuò)誤處理器就會(huì)明白該錯(cuò)誤級(jí)別是critical,并相應(yīng)地調(diào)用longjmp()來(lái)中斷當(dāng)前程序流程并離開call_function()函數(shù),甚至根本不會(huì)執(zhí)行到efree(lcase_fname)這一行。你可能想把efree()代碼行移動(dòng)到zend_error()代碼行的上面;但是,調(diào)用這個(gè)call_function()例程的代碼行會(huì)怎么樣呢?fname本身很可能就是一個(gè)分配的字符串,并且,在它被錯(cuò)誤消息處理使用完之前,你根本不能釋放它。

      注意,這個(gè)php_error_docref()函數(shù)是trigger_error()函數(shù)的一個(gè)內(nèi)部等價(jià)實(shí)現(xiàn)。它的第一個(gè)參數(shù)是一個(gè)將被添加到docref的可選的文檔引用。第三個(gè)參數(shù)可以是任何我們熟悉的E_*家族常量,用于指示錯(cuò)誤的嚴(yán)重程度。第四個(gè)參數(shù)(最后一個(gè))遵循printf()風(fēng)格的格式化和變量參數(shù)列表式樣。

      四、 Zend內(nèi)存管理器

      在上面的"跳出"請(qǐng)求期間解決內(nèi)存泄漏的方案之一是:使用Zend內(nèi)存管理(ZendMM)層。引擎的這一部分非常類似于操作系統(tǒng)的內(nèi)存管理行為-分配內(nèi)存給調(diào)用程序。區(qū)別在于,它處于進(jìn)程空間中非常低的位置而且是"請(qǐng)求感知"的;這樣以來(lái),當(dāng)一個(gè)請(qǐng)求結(jié)束時(shí),它能夠執(zhí)行與OS在一個(gè)進(jìn)程終止時(shí)相同的行為。也就是說(shuō),它會(huì)隱式地釋放所有的為該請(qǐng)求所占用的內(nèi)存。圖1展示了ZendMM與OS以及PHP進(jìn)程之間的關(guān)系。

    網(wǎng)管必讀深入探討PHP中的內(nèi)存管理問題(2)
    圖1.Zend內(nèi)存管理器代替系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)針對(duì)每一種請(qǐng)求的內(nèi)存分配。

      除了提供隱式內(nèi)存清除功能之外,ZendMM還能夠根據(jù)php.ini中memory_limit的設(shè)置控制每一種內(nèi)存請(qǐng)求的用法。如果一個(gè)腳本試圖請(qǐng)求比系統(tǒng)中可用內(nèi)存更多的內(nèi)存,或大于它每次應(yīng)該請(qǐng)求的最大量,那么,ZendMM將自動(dòng)地發(fā)出一個(gè)E_ERROR消息并且啟動(dòng)相應(yīng)的"跳出"進(jìn)程。這種方法的一個(gè)額外優(yōu)點(diǎn)在于,大多數(shù)內(nèi)存分配調(diào)用的返回值并不需要檢查,因?yàn)槿绻〉脑拰?huì)導(dǎo)致立即跳轉(zhuǎn)到引擎的退出部分。

      把PHP內(nèi)部代碼和OS的實(shí)際的內(nèi)存管理層"鉤"在一起的原理并不復(fù)雜:所有內(nèi)部分配的內(nèi)存都要使用一組特定的可選函數(shù)實(shí)現(xiàn)。例如,PHP代碼不是使用malloc(16)來(lái)分配一個(gè)16字節(jié)內(nèi)存塊而是使用了emalloc(16)。除了實(shí)現(xiàn)實(shí)際的內(nèi)存分配任務(wù)外,ZendMM還會(huì)使用相應(yīng)的綁定請(qǐng)求類型來(lái)標(biāo)志該內(nèi)存塊;這樣以來(lái),當(dāng)一個(gè)請(qǐng)求"跳出"時(shí),ZendMM可以隱式地釋放它。

      經(jīng)常情況下,內(nèi)存一般都需要被分配比單個(gè)請(qǐng)求持續(xù)時(shí)間更長(zhǎng)的一段時(shí)間。這種類型的分配(因其在一次請(qǐng)求結(jié)束之后仍然存在而被稱為"永久性分配"),可以使用傳統(tǒng)型內(nèi)存分配器來(lái)實(shí)現(xiàn),因?yàn)檫@些分配并不會(huì)添加ZendMM使用的那些額外的相應(yīng)于每種請(qǐng)求的信息。然而有時(shí),直到運(yùn)行時(shí)刻才會(huì)確定是否一個(gè)特定的分配需要永久性分配,因此ZendMM導(dǎo)出了一組幫助宏,其行為類似于其它的內(nèi)存分配函數(shù),但是使用最后一個(gè)額外參數(shù)來(lái)指示是否為永久性分配。

      如果你確實(shí)想實(shí)現(xiàn)一個(gè)永久性分配,那么這個(gè)參數(shù)應(yīng)該被設(shè)置為1;在這種情況下,請(qǐng)求是通過傳統(tǒng)型malloc()分配器家族進(jìn)行傳遞的。然而,如果運(yùn)行時(shí)刻邏輯認(rèn)為這個(gè)塊不需要永久性分配;那么,這個(gè)參數(shù)可以被設(shè)置為零,并且調(diào)用將會(huì)被調(diào)整到針對(duì)每種請(qǐng)求的內(nèi)存分配器函數(shù)。

      例如,pemalloc(buffer_len,1)將映射到malloc(buffer_len),而pemalloc(buffer_len,0)將被使用下列語(yǔ)句映射到emalloc(buffer_len):

    #define in Zend/zend_alloc.h:
    #define pemalloc(size, persistent) ((persistent)?malloc(size): emalloc(size))

      所有這些在ZendMM中提供的分配器函數(shù)都能夠從下表中找到其更傳統(tǒng)的對(duì)應(yīng)實(shí)現(xiàn)。

      表格1展示了ZendMM支持下的每一個(gè)分配器函數(shù)以及它們的e/pe對(duì)應(yīng)實(shí)現(xiàn):

      表格1.傳統(tǒng)型相對(duì)于PHP特定的分配器。

    分配器函數(shù) e/pe對(duì)應(yīng)實(shí)現(xiàn)
    void *malloc(size_t count); void *emalloc(size_t count);void *pemalloc(size_t count,char persistent);
    void *calloc(size_t count); void *ecalloc(size_t count);void *pecalloc(size_t count,char persistent);
    void *realloc(void *ptr,size_t count); void *erealloc(void *ptr,size_t count);
    void *perealloc(void *ptr,size_t count,char persistent);
    void *strdup(void *ptr); void *estrdup(void *ptr);void *pestrdup(void *ptr,char persistent);
    void free(void *ptr); void efree(void *ptr);
    void pefree(void *ptr,char persistent);

      你可能會(huì)注意到,即使是pefree()函數(shù)也要求使用永久性標(biāo)志。這是因?yàn)樵谡{(diào)用pefree()時(shí),它實(shí)際上并不知道是否ptr是一種永久性分配。針對(duì)一個(gè)非永久性分配調(diào)用free()能夠?qū)е码p倍的空間釋放,而針對(duì)一種永久性分配調(diào)用efree()有可能會(huì)導(dǎo)致一個(gè)段錯(cuò)誤,因?yàn)閮?nèi)存管理器會(huì)試圖查找并不存在的管理信息。因此,你的代碼需要記住它分配的數(shù)據(jù)結(jié)構(gòu)是否是永久性的。

      除了分配器函數(shù)核心部分外,還存在其它一些非常方便的ZendMM特定的函數(shù),例如:

    void *estrndup(void *ptr,int len);

      該函數(shù)能夠分配len+1個(gè)字節(jié)的內(nèi)存并且從ptr處復(fù)制len個(gè)字節(jié)到最新分配的塊。這個(gè)estrndup()函數(shù)的行為可以大致描述如下:

    void *estrndup(void *ptr, int len)
    {
     char *dst = emalloc(len + 1);
     memcpy(dst, ptr, len);
     dst[len] = 0;
     return dst;
    }

      在此,被隱式放置在緩沖區(qū)最后的NULL字節(jié)可以確保任何使用estrndup()實(shí)現(xiàn)字符串復(fù)制操作的函數(shù)都不需要擔(dān)心會(huì)把結(jié)果緩沖區(qū)傳遞給一個(gè)例如printf()這樣的希望以為NULL為結(jié)束符的函數(shù)。當(dāng)使用estrndup()來(lái)復(fù)制非字符串?dāng)?shù)據(jù)時(shí),最后一個(gè)字節(jié)實(shí)質(zhì)上都浪費(fèi)了,但其中的利明顯大于弊。

    void *safe_emalloc(size_t size, size_t count, size_t addtl);
    void *safe_pemalloc(size_t size, size_t count,size_t addtl,char persistent);

      這些函數(shù)分配的內(nèi)存空間最終大小是((size*count)+addtl)。你可以會(huì)問:"為什么還要提供額外函數(shù)呢?為什么不使用一個(gè)emalloc/pemalloc呢?"原因很簡(jiǎn)單:為了安全。盡管有時(shí)候可能性相當(dāng)小,但是,正是這一"可能性相當(dāng)小"的結(jié)果導(dǎo)致宿主平臺(tái)的內(nèi)存溢出。這可能會(huì)導(dǎo)致分配負(fù)數(shù)個(gè)數(shù)的字節(jié)空間,或更有甚者,會(huì)導(dǎo)致分配一個(gè)小于調(diào)用程序要求大小的字節(jié)空間。而safe_emalloc()能夠避免這種類型的陷井-通過檢查整數(shù)溢出并且在發(fā)生這樣的溢出時(shí)顯式地預(yù)以結(jié)束。

      注意,并不是所有的內(nèi)存分配例程都有一個(gè)相應(yīng)的p*對(duì)等實(shí)現(xiàn)。例如,不存在pestrndup(),并且在PHP 5.1版本前也不存在safe_pemalloc()。

      五、 引用計(jì)數(shù)

      慎重的內(nèi)存分配與釋放對(duì)于PHP(它是一種多請(qǐng)求進(jìn)程)的長(zhǎng)期性能有極其重大的影響;但是,這還僅是問題的一半。為了使一個(gè)每秒處理上千次點(diǎn)擊的服務(wù)器高效地運(yùn)行,每一次請(qǐng)求都需要使用盡可能少的內(nèi)存并且要盡可能減少不必要的數(shù)據(jù)復(fù)制操作。請(qǐng)考慮下列PHP代碼片斷:

    <?php
    $a = 'Hello World';
    $b = $a;
    unset($a);
    ?>

      在第一次調(diào)用之后,只有一個(gè)變量被創(chuàng)建,并且一個(gè)12字節(jié)的內(nèi)存塊指派給它以便存儲(chǔ)字符串"Hello World",還包括一個(gè)結(jié)尾處的NULL字符。現(xiàn)在,讓我們來(lái)觀察后面的兩行:$b被置為與變量$a相同的值,然后變量$a被釋放。

      如果PHP因每次變量賦值都要復(fù)制變量?jī)?nèi)容的話,那么,對(duì)于上例中要復(fù)制的字符串還需要復(fù)制額外的12個(gè)字節(jié),并且在數(shù)據(jù)復(fù)制期間還要進(jìn)行另外的處理器加載。這一行為乍看起來(lái)有點(diǎn)荒謬,因?yàn)楫?dāng)?shù)谌写a出現(xiàn)時(shí),原始變量被釋放,從而使得整個(gè)數(shù)據(jù)復(fù)制顯得完全不必要。其實(shí),我們不妨再遠(yuǎn)一層考慮,讓我們?cè)O(shè)想當(dāng)一個(gè)10MB大小的文件的內(nèi)容被裝載到兩個(gè)變量中時(shí)會(huì)發(fā)生什么。這將會(huì)占用20MB的空間,此時(shí),10已經(jīng)足夠了。引擎會(huì)把那么多的時(shí)間和內(nèi)存浪費(fèi)在這樣一種無(wú)用的努力上嗎?

      你應(yīng)該知道,PHP的設(shè)計(jì)者早已深諳此理。

      記住,在引擎中,變量名和它們的值實(shí)際上是兩個(gè)不同的概念。值本身是一個(gè)無(wú)名的zval*存儲(chǔ)體(在本例中,是一個(gè)字符串值),它被通過zend_hash_add()賦給變量$a。如果兩個(gè)變量名都指向同一個(gè)值,會(huì)發(fā)生什么呢?

    {
     zval *helloval;
     MAKE_STD_ZVAL(helloval);
     ZVAL_STRING(helloval, "Hello World", 1);
     zend_hash_add(EG(active_symbol_table), "a", sizeof("a"),&helloval, sizeof(zval*), NULL);
     zend_hash_add(EG(active_symbol_table), "b", sizeof("b"),&helloval, sizeof(zval*), NULL);
    }

      此時(shí),你可以實(shí)際地觀察$a或$b,并且會(huì)看到它們都包含字符串"Hello World"。遺憾的是,接下來(lái),你繼續(xù)執(zhí)行第三行代碼"unset($a);"。此時(shí),unset()并不知道$a變量指向的數(shù)據(jù)還被另一個(gè)變量所使用,因此它只是盲目地釋放掉該內(nèi)存。任何隨后的對(duì)變量$b的存取都將被分析為已經(jīng)釋放的內(nèi)存空間并因此導(dǎo)致引擎崩潰。

      這個(gè)問題可以借助于zval(它有好幾種形式)的第四個(gè)成員refcount加以解決。當(dāng)一個(gè)變量被首次創(chuàng)建并賦值時(shí),它的refcount被初始化為1,因?yàn)樗患俣▋H由最初創(chuàng)建它時(shí)相應(yīng)的變量所使用。當(dāng)你的代碼片斷開始把helloval賦給$b時(shí),它需要把refcount的值增加為2;這樣以來(lái),現(xiàn)在該值被兩個(gè)變量所引用:

    {
     zval *helloval;
     MAKE_STD_ZVAL(helloval);
     ZVAL_STRING(helloval, "Hello World", 1);
     zend_hash_add(EG(active_symbol_table), "a", sizeof("a"),&helloval, sizeof(zval*), NULL);
     ZVAL_ADDREF(helloval);
     zend_hash_add(EG(active_symbol_table), "b", sizeof("b"),&helloval,sizeof(zval*),NULL);
    }

      現(xiàn)在,當(dāng)unset()刪除原變量的$a相應(yīng)的副本時(shí),它就能夠從refcount參數(shù)中看到,還有另外其他人對(duì)該數(shù)據(jù)感興趣;因此,它應(yīng)該只是減少refcount的計(jì)數(shù)值,然后不再管它。

      六、 寫復(fù)制(Copy on Write)

      通過refcounting來(lái)節(jié)約內(nèi)存的確是不錯(cuò)的主意,但是,當(dāng)你僅想改變其中一個(gè)變量的值時(shí)情況會(huì)如何呢?為此,請(qǐng)考慮下面的代碼片斷:

    <?php
    $a = 1;
    $b = $a;
    $b += 5;
    ?>

      通過上面的邏輯流程,你當(dāng)然知道$a的值仍然等于1,而$b的值最后將是6。并且此時(shí),你還知道,Zend在盡力節(jié)省內(nèi)存-通過使$a和$b都引用相同的zval(見第二行代碼)。那么,當(dāng)執(zhí)行到第三行并且必須改變$b變量的值時(shí),會(huì)發(fā)生什么情況呢?

      回答是,Zend要查看refcount的值,并且確保在它的值大于1時(shí)對(duì)之進(jìn)行分離。在Zend引擎中,分離是破壞一個(gè)引用對(duì)的過程,正好與你剛才看到的過程相反:

    zval *get_var_and_separate(char *varname, int varname_len TSRMLS_DC)
    {
     zval **varval, *varcopy;
     if (zend_hash_find(EG(active_symbol_table),varname, varname_len + 1, (void**)&varval) == FAILURE) {
      /* 變量根本并不存在-失敗而導(dǎo)致退出*/
      return NULL;
     }
     if ((*varval)->refcount < 2) {
      /* varname是唯一的實(shí)際引用,
      *不需要進(jìn)行分離
      */
      return *varval;
     }
     /* 否則,再?gòu)?fù)制一份zval*的值*/
     MAKE_STD_ZVAL(varcopy);
     varcopy = *varval;
     /* 復(fù)制任何在zval*內(nèi)的已分配的結(jié)構(gòu)*/
     zval_copy_ctor(varcopy);
     /*刪除舊版本的varname
     *這將減少該過程中varval的refcount的值
     */
     zend_hash_del(EG(active_symbol_table), varname, varname_len + 1);
     /*初始化新創(chuàng)建的值的引用計(jì)數(shù),并把它依附到
     * varname變量
     */
     varcopy->refcount = 1;
     varcopy->is_ref = 0;
     zend_hash_add(EG(active_symbol_table), varname, varname_len + 1,&varcopy, sizeof(zval*), NULL);
     /*返回新的zval* */
     return varcopy;
    }

      現(xiàn)在,既然引擎有一個(gè)僅為變量$b所擁有的zval*(引擎能知道這一點(diǎn)),所以它能夠把這個(gè)值轉(zhuǎn)換成一個(gè)long型值并根據(jù)腳本的請(qǐng)求給它增加5。

      七、 寫改變(change-on-write)

      引用計(jì)數(shù)概念的引入還導(dǎo)致了一個(gè)新的數(shù)據(jù)操作可能性,其形式從用戶空間腳本管理器看來(lái)與"引用"有一定關(guān)系。請(qǐng)考慮下列的用戶空間代碼片斷:

    <?php
    $a = 1;
    $b = &$a;
    $b += 5;
    ?>

      在上面的PHP代碼中,你能看出$a的值現(xiàn)在為6,盡管它一開始為1并且從未(直接)發(fā)生變化。之所以會(huì)發(fā)生這種情況是因?yàn)楫?dāng)引擎開始把$b的值增加5時(shí),它注意到$b是一個(gè)對(duì)$a的引用并且認(rèn)為"我可以改變?cè)撝刀槐胤蛛x它,因?yàn)槲蚁胧顾械囊米兞慷寄芸吹竭@一改變"。

      但是,引擎是如何知道的呢?很簡(jiǎn)單,它只要查看一下zval結(jié)構(gòu)的第四個(gè)和最后一個(gè)元素(is_ref)即可。這是一個(gè)簡(jiǎn)單的開/關(guān)位,它定義了該值是否實(shí)際上是一個(gè)用戶空間風(fēng)格引用集的一部分。在前面的代碼片斷中,當(dāng)執(zhí)行第一行時(shí),為$a創(chuàng)建的值得到一個(gè)refcount為1,還有一個(gè)is_ref值為0,因?yàn)樗鼉H為一個(gè)變量($a)所擁有并且沒有其它變量對(duì)它產(chǎn)生寫引用改變。在第二行,這個(gè)值的refcount元素被增加為2,除了這次is_ref元素被置為1之外(因?yàn)槟_本中包含了一個(gè)"&"符號(hào)以指示是完全引用)。

      最后,在第三行,引擎再一次取出與變量$b相關(guān)的值并且檢查是否有必要進(jìn)行分離。這一次該值沒有被分離,因?yàn)榍懊鏇]有包括一個(gè)檢查。下面是get_var_and_separate()函數(shù)中與refcount檢查有關(guān)的部分代碼:

    if ((*varval)->is_ref || (*varval)->refcount < 2) {
     /* varname是唯一的實(shí)際引用,
     * 或者它是對(duì)其它變量的一個(gè)完全引用
     *任何一種方式:都沒有進(jìn)行分離
     */
     return *varval;
    }

      這一次,盡管refcount為2,卻沒有實(shí)現(xiàn)分離,因?yàn)檫@個(gè)值是一個(gè)完全引用。引擎能夠自由地修改它而不必關(guān)心其它變量值的變化。

      八、 分離問題

      盡管已經(jīng)存在上面討論到的復(fù)制和引用技術(shù),但是還存在一些不能通過is_ref和refcount操作來(lái)解決的問題。請(qǐng)考慮下面這個(gè)PHP代碼塊:

    <?php
    $a = 1;
    $b = $a;
    $c = &$a;
    ?>

      在此,你有一個(gè)需要與三個(gè)不同的變量相關(guān)聯(lián)的值。其中,兩個(gè)變量是使用了"change-on-write"完全引用方式,而第三個(gè)變量處于一種可分離的"copy-on-write"(寫復(fù)制)上下文中。如果僅使用is_ref和refcount來(lái)描述這種關(guān)系,有哪些值能夠工作呢?

      回答是:沒有一個(gè)能工作。在這種情況下,這個(gè)值必須被復(fù)制到兩個(gè)分離的zval*中,盡管兩者都包含完全相同的數(shù)據(jù)(見圖2)。

    網(wǎng)管必讀深入探討PHP中的內(nèi)存管理問題(4)
    圖2.引用時(shí)強(qiáng)制分離

      同樣,下列代碼塊將引起相同的沖突并且強(qiáng)迫該值分離出一個(gè)副本(見圖3)。

    網(wǎng)管必讀深入探討PHP中的內(nèi)存管理問題(4)
    圖3.復(fù)制時(shí)強(qiáng)制分離

    <?php
    $a = 1;
    $b = &$a;
    $c = $a;
    ?>

      注意,在這里的兩種情況下,$b都與原始的zval對(duì)象相關(guān)聯(lián),因?yàn)樵诜蛛x發(fā)生時(shí)引擎無(wú)法知道介于到該操作當(dāng)中的第三個(gè)變量的名字。

      九、 總結(jié)

      PHP是一種托管語(yǔ)言。從普通用戶角度來(lái)看,這種仔細(xì)地控制資源和內(nèi)存的方式意味著更為容易地進(jìn)行原型開發(fā)并導(dǎo)致出現(xiàn)更少的沖突。然而,當(dāng)我們深入"內(nèi)里"之后,一切的承諾似乎都不復(fù)存在,最終還要依賴于真正有責(zé)任心的開發(fā)者來(lái)維持整個(gè)運(yùn)行時(shí)刻環(huán)境的一致性。

    posted @ 2009-03-02 17:52 小馬歌 閱讀(150) | 評(píng)論 (0)編輯 收藏
     
    1. 安裝postfix
       tar -zxf postfix-2.4.6.tar.gz
       cd postfix-2.4.6
       mv /usr/sbin/sendmail /usr/sbin/sendmail.OFF
       mv /usr/bin/newaliases /usr/bin/newaliases.OFF
       mv /usr/bin/mailq /usr/bin/mailq.OFF
       chmod 755 /usr/sbin/sendmail.OFF /usr/bin/newaliases.OFF /usr/bin/mailq.OFF
       vi /etc/passwd:
               postfix:*:12345:12345:postfix:/no/where:/no/shell
       vi  /etc/group:
               postfix:*:12345:

    或者用命令
        groupadd postfix -c 12345
        useradd -u 12345 -g 12345 -c postfix -d/dev/null -s/bin/false postfix
        groupadd -c 54321 postdrop

    開始安裝
      make
      make install

    一路enter直到安裝完成

    2.安裝 vm-pop3d (為了收郵件)
      tar zxvf vm-pop3d-1.1.6.tar.gz
      cd vm-pop3d-1.1.6
      ./configure --prefix=/usr/local/pop3 --enable-pam  --enable-virtual --enable-ip-based-virtual
      make
      make install


    vi /etc/xinetd.d/pop3
    # default: off
    # description: The rsync server is a good addition to an ftp server, as it \
    #       allows crc checksumming etc.
    service pop3 {      
    disable = no      
    socket_type     = stream      
    wait            = no      
    protocol        = tcp      
    user            = root      
    server          = /usr/local/pop3/sbin/vm-pop3d
    }
    然后就service xinetd start 啟動(dòng)pop3
    3.配置安裝完的postfix配置目錄在/etc/postfix下,主要配置main.cf,粗體部分是我修改過的,mail.jq.com配hosts
    vi /etc/postfix/main.cf
    queue_directory = /var/spool/postfix
    command_directory = /usr/sbin
    daemon_directory = /usr/libexec/postfix
    mail_owner = postfix
    myhostname = mail.jq.com
    inet_interfaces = all
    mydestination = $myhostname
    unknown_local_recipient_reject_code = 550
    mynetworks = 192.168.0.0/16, 127.0.0.0/8, 0.0.0.0/0
    alias_maps = hash:/etc/aliases  
    alias_database = hash:/etc/aliases
    local_recipient_maps = $alias_maps unix:passwd.byname  
    debug_peer_level = 2  
    debugger_command =        PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin        
    xxgdb $daemon_directory/$process_name $process_id & sleep 5  
    sendmail_path = /usr/sbin/sendmail  
    newaliases_path = /usr/bin/newaliases  
    mailq_path = /usr/bin/mailq  
    setgid_group = postdrop  
    html_directory = no  
    manpage_directory = /usr/local/man  
    sample_directory = /etc/postfix  
    readme_directory = no
    啟動(dòng)postfix: postfix start
    注意iptables要開放25和110端口,hosts.allow加入vm-pop3d:all
    此時(shí)應(yīng)該就可以用foxmail收發(fā)郵件了,我測(cè)試的時(shí)候一直提示輸入密碼,輸入系統(tǒng)密碼又不對(duì)看日志cat /var/log/maillog
      Dec  3 09:18:08 zhangwenhao1 vm-pop3d[12632]: Couldn't open password file: /etc/virtual/mail.jq.com/passwd
    之后
      mkdir -p /etc/virtual/mail.jq.com/ ln -s /etc/shadow /etc/virtual/mail.jq.com/passwd
    再次測(cè)試,發(fā)送接收郵件成功,這里是使用系統(tǒng)的帳戶,也可以自己新建虛擬賬戶,利用apache的htpasswd
    /usr/local/apache2/bin/htpasswd -c /etc/virtual/mail.jq.com/passwd jq
    輸入密碼,就可以使用虛擬帳戶收發(fā)郵件了
    posted @ 2009-02-26 14:10 小馬歌 閱讀(1395) | 評(píng)論 (0)編輯 收藏
    僅列出標(biāo)題
    共95頁(yè): First 上一頁(yè) 71 72 73 74 75 76 77 78 79 下一頁(yè) Last 
     
    主站蜘蛛池模板: a级毛片在线视频免费观看| 亚洲高清国产拍精品26U| 99亚洲男女激情在线观看| 四虎影院免费在线播放| 亚洲中文字幕一二三四区| 日韩欧美一区二区三区免费观看 | 日本免费一区二区三区四区五六区 | 香蕉免费看一区二区三区| 亚洲中文久久精品无码ww16| 久久国产精品免费| 亚洲人成网亚洲欧洲无码久久| 一二三四在线观看免费中文在线观看| 亚洲国产高清精品线久久| www成人免费视频| 狠狠亚洲婷婷综合色香五月排名| 福利免费在线观看| 亚洲av无码乱码国产精品| 久久这里只精品热免费99| 亚洲黄色免费网址| av无码久久久久不卡免费网站| 狠狠色香婷婷久久亚洲精品| 国内自产拍自a免费毛片| 午夜亚洲乱码伦小说区69堂| 亚洲国产精品无码久久久久久曰| 国产无遮挡色视频免费观看性色 | 国产免费人人看大香伊| xxxxxx日本处大片免费看 | 亚洲成a人片在线不卡一二三区 | 亚洲中文字幕无码永久在线| 无人在线观看免费高清| 亚洲一区二区三区不卡在线播放| 日韩高清在线免费观看| 一个人免费观看日本www视频| 国产亚洲无线码一区二区| free哆啪啪免费永久| 亚洲色偷精品一区二区三区 | 亚洲人成在线免费观看| 免费看AV毛片一区二区三区| 日韩久久无码免费毛片软件| 亚洲国产精品VA在线观看麻豆| ww在线观视频免费观看|