原始碼位址
看到像這個給tinyhttpd寫readme的倉庫都有1k star的時候,我真的好氣?,所以我也寫乙個用c寫http靜態檔案伺服器的教程,而且效能更好。
c socket程式設計面向的是傳輸層。我們在這一層上來收發http報文。
http請求報文格式如下:
由於我們是靜態檔案伺服器,所以有效的請求報文是 get url 的格式。我們只要解析這個url,然後傳送對應的檔案就ok了。這個是基本的思路。
我仿照unp中對函式進行包裝的方式。對基礎函式進行包裝,在**中只使用包裝過的函式。
unix函式大多會將函式的呼叫狀態作為返回值。如socket函式,如果返回值小於零,則是呼叫出錯,這種情況我們直接結束程序並報錯。
伺服器啟動並監聽的流程是這樣的:首先呼叫socket()建立乙個服務端的套接字,然後使用bind()將套接字繫結在乙個指定的埠上。呼叫listen()將套接字從closed狀態轉換到listen狀態。而accept會返回已連線佇列的對頭。我們對accept返回的描述符的讀寫就是對客戶端的收發操作。
這篇教程選用的併發模型是執行緒池,每個執行緒分別accept的形式。
reqhandler這個struct存放的是對客戶端描述符的處理函式和在pthread_t陣列的下標。下標用於後面的pthread_create
主程序在建立完執行緒後任務就完成了,所以它一直阻塞等待就好。
tptr = calloc(thread_num, sizeof(pthread_t));
// tptr是乙個pthread_t的陣列。在啟動的時候可給出執行緒池執行緒的數量,不指明則使用預設值8。
reqhandler rh;
rh.handler = accept_request;
for (int i = 0; i < nthreads; i++)
for ( ; ; )
pause(); // everything done by threads
pthread_create(&tptr[rh.index], null, &thread_main, (void *) (rh.handler));
在各個執行緒中分別accept,這個有個問題,他們不應該同時accept。所以我們在進入accept這個函式前加上互斥鎖。
pthread_mutex_lock(&mmlock);
connfd = accept(listenfd, cliaddr, &clilen);
pthread_mutex_unlock(&mmlock);
在伺服器搭起來之後,我們就可以幹正事了。accept_request
這個函式解析出http的請求方法和url並作出響應。
我們知道http的每一行是以/r/n
結束,那麼getline該怎麼做呢?乙個字元乙個字元地讀,並逐一判斷是否為/r/n
序列的方法顯然比較慢。所以我們做乙個自己的緩衝區。預先在客戶端描述符connfd讀入多個字元。再在緩衝區裡乙個字元乙個字元地判斷。緩衝區讀完後,再讀一次connfd。這樣能大大減少讀取connfd的次數。
獲取到http的請求方法後,如果方法不是get,我們直接返回501錯誤。說明這個方法我們還沒有實現。
可能有人會對下面這種寫法感到疑惑。其實編譯器在做預處理的時候會把連著的字串合併的。所以下面這種寫法跟寫在一對雙引號裡是一樣的。
void
unimplemented(int sockfd)
然後判斷url的檔案是否存在。這裡我們多做了一步處理,如果url是以/
結尾的,瀏覽器會自動給它加上index.html
,所以我們也按照這個來。
我們用open的形式開啟檔案,而不是標準io的fopen。open能拿到該檔案的描述符。這在我們下一步傳輸檔案時比較方便。如果檔案不存在,直接返回404。
void
serve_file(int sockfd, const char *filepath)
else
}
向客戶端傳送檔案,還得設定好響應報文中content-type的值,告訴對方這是乙個什麼檔案。這裡我們需要一張表,根據檔案的字尾名查詢content-type。自然是使用hash表,衝突用鍊錶的形式解決。具體請看原始碼。
傳輸檔案時,就是一對read write,unix一切皆檔案的優雅就此體現。
void
send_file(int sockfd, int filefd)
}
寫乙個索引伺服器
今天把 jaxb 返回的 xml 物件 轉到了 lucene 的 document 然後仍給 index search 一把。還算順利搞定。接下來開始解決網路介面。寫乙個基於netty的索引伺服器。接收client仍過來的xml資料報。關於netty的資料除了 url 還有一部分中文的。url 大致...
自己動手開發乙個 Web 伺服器(一)
自己動手開發 web 伺服器 會分為三個部分,將介紹如何從頭開發乙個簡易 web 伺服器。我們這就開始吧。首先,到底什麼是 web 伺服器?http請求 響應 簡而言之,它是在物理伺服器上搭建的乙個網路連線伺服器 networking server 永久地等待客戶端傳送請求。當伺服器收到請求之後,它...
寫乙個http介面服務
主要要提供以下功能 1 可提供http介面通訊,實現服務端和客戶端的應答 2 通訊資料格式為json 3 可根據介面需求運算元據庫增刪改查 4 介面通訊過程日誌記錄 5 可與其他模組進行內部通訊 寫了以上內容後,開始考慮如何實現了。目前使用jdbctemplate實現對資料庫mysql的操作,但sp...