nginx資料接收和發送的套介面選擇 1、資料的接收:// readv將讀入的資料按上述同樣順序散布讀到緩衝區中。readv總是先填滿一個緩衝區,然後再填寫下一個。readv返回讀到的總位元組數。如果遇到檔案結尾,已無資料可讀,則返回0。 www.2cto.com
n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); 放到列表 中 iov = ngx_array_push(&vec); 2、發送大量資料的處理: 讀取資料 if (iov == NULL) { return NGX_CHAIN_ERROR; } 設定套介面// TCP_NODELAY選項禁止Nagle演算法。// Nagle演算法通過將未確認的資料存入緩衝區直到蓄足一個包一起發送的方法,來減少主機發送的零碎小資料包的數目。 www.2cto.com // 但對於某些應用來說,這種演算法將降低系統效能。所以TCP_NODELAY可用來將此演算法關閉。// 應用程式編寫者只有在確切瞭解它的效果並確實需要的情況下,才設定TCP_NODELAY選項,因為設定後對網路效能有明顯的負面影響。
// TCP_NODELAY是唯一使用IPPROTO_TCP層的選項,其他所有選項都使用SOL_SOCKET層。 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { err = ngx_errno;發送資料 // sendfile()是作用於資料拷貝在兩個檔案描述符之間的操作函數.這個拷貝操作是核心中操作的,所以稱為"零拷貝".sendfile函數比起read和write函數高效得多,因為read和write是要把資料拷貝到使用者應用程式層操作. www.2cto.com //// 參數說明:// out_fd 是已經開啟了,用於寫操作(write)的檔案描述符;// in_fd 是已經開啟了,用於讀操作(read)的檔案描述符;
// offset 位移量;表示sendfile函數從in_fd中的哪一位移量開始讀取資料.如果是零表示從檔案的開始讀,否則從相應的便宜量讀取.如果是迴圈讀取的時候,下一次offset值應為sendfile函數傳回值加上本次的offset的值.// count是在兩個描述符之間拷貝的位元組數(bytes)// sendfile()在兩種情況下才體現優勢,但我卻沒有環境測試://// 1. 大並發量的檔案伺服器或HTTP伺服器;// 2. 記憶體資源緊張的嵌入式系統;// 3.和setsockopt一起使用// 為什麼要用sendfile? www.2cto.com // 原因很簡單,項目中有個需求是後端程式負責把源檔案打包加密產生目標檔案,然後程式讀取目標檔案返回給瀏覽器;這種做法有個致命的缺陷就是佔用大量後端程式資源,如果遇到一些訪客下載速度巨慢,就會造成大量資源被長期佔用得不到釋放,很快後端程式就會因為沒有資源可用而無法正常提供服務。 通常表現就是nginx報502錯誤!其次在nginx內部我還想實現“由nginx檢查目標檔案是否存在,如果存在的話就直接返回給瀏覽器而無需經過後端程式的處理”,這樣一來後端程式只是負責產生目標檔案,一單目標檔案被產生,基本上就不再提供服務,而nginx則提供全靜態檔案瀏覽服務。可想而知,效能的提升還是大很多的!//// 怎麼啟用sendfile?// 詳細配置步驟就不說了,官方wiki已經說明的比較清楚。只提一下注意點吧:// 1,location 必須 被定義為 internal;// 2,如果在location中使用alias 一定要注意目錄結尾的“/”;
// 3,要注意location 匹配時盡量只用目錄名。 我在測試中遇到抓狂的問題。// www.2cto.com // 先說一下我最終的方案:// 1,增加一個location作為目標檔案的檢查,如果存在 就發給internal的location繼續處理,如果不存在就rewrite到後端程式處理; //下載之類可能使用 //主要提高伺服器資源效能 rc = sendfile(c->fd, file->file->fd, &offset, file_size); //大資料發送 這就是所謂的零拷貝技術,所以常用來作高效能檔案伺服器。 3、發送少量資料的處理: 讀取資料 if (iov == NULL) { return NGX_CHAIN_ERROR; } 發送資料 www.2cto.com //應該是小資料發送// 將多個資料存放區在一起,將駐留在兩個或更多的不串連的緩衝區中的資料一次寫出去。// UNIX和WINSOCK提供了不同的實現方法UNIX系統下,使用writev,可以指定一系列的緩衝區,收集要寫的資料,使可以安排資料儲存在多個緩衝區中,然後同時寫出去,從而避免出現Nagle和延遲ACK演算法的相互影響。 rc = writev(c->fd, header.elts, header.nelts);