導航:首頁 > 源碼編譯 > epoll源碼原理

epoll源碼原理

發布時間:2022-10-21 03:58:23

① nginx 源碼 epoll模塊在哪個文件

linux平台上,Nginx使用epoll完成事件驅動,實現高並發;本文將不對epoll本身進行介紹(網上一堆一堆的文章介紹epoll的原理及使用方法,甚至源碼分析等),僅看一下Nginx是如何使用epoll的。

Nginx在epoll模塊中定義了好幾個函數,這些函數基本都是作為回調注冊到事件抽象層的對應介面上,從而實現了事件驅動的具體化,我們看如下的一段代碼:

[cpp] view plain print?
ngx_event_mole_t ngx_epoll_mole_ctx = {
&epoll_name,
ngx_epoll_create_conf, /* create configuration */
ngx_epoll_init_conf, /* init configuration */
{
ngx_epoll_add_event, /* add an event */
ngx_epoll_del_event, /* delete an event */
ngx_epoll_add_event, /* enable an event */
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
NULL, /* process the changes */
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
}
};

這段代碼就是epoll的相關函數注冊到事件抽象層,這里所謂的事件抽象層在前面的博文中有提過,就是Nginx為了方便支持和開發具體的I/O模型,從而實現的一層抽象。代碼後面的注釋將功能說明得很詳細了,本文就只重點關注ngx_epoll_init和ngx_epoll_process_events兩個函數,其他幾個函數就暫且忽略了。

ngx_epoll_init主要是完成epoll的相關初始化工作,代碼分析如下:

[cpp] view plain print?
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
/*取得epoll模塊的配置結構*/
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_mole);
/*ep是epoll模塊定義的一個全局變數,初始化為-1*/
if (ep == -1) {
/*創一個epoll對象,容量為總連接數的一半*/
ep = epoll_create(cycle->connection_n / 2);
if (ep == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"epoll_create() failed");
return NGX_ERROR;
}
}
/*nevents也是epoll模塊定義的一個全局變數,初始化為0*/
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}

/*event_list存儲產生事件的數組*/
event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
cycle->log);
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;
/*初始化全局變數ngx_io, ngx_os_is定義為:
ngx_os_io_t ngx_os_io = {
ngx_unix_recv,
ngx_readv_chain,
ngx_udp_unix_recv,
ngx_unix_send,
ngx_writev_chain,
0
};(位於src/os/unix/ngx_posix_init.c)
*/
ngx_io = ngx_os_io;
/*這里就是將epoll的具體介面函數注冊到事件抽象層介面ngx_event_actions上。
具體是上文提到的ngx_epoll_mole_ctx中封裝的如下幾個函數
ngx_epoll_add_event,
ngx_epoll_del_event,
ngx_epoll_add_event,
ngx_epoll_del_event,
ngx_epoll_add_connection,
ngx_epoll_del_connection,
ngx_epoll_process_events,
ngx_epoll_init,
ngx_epoll_done,
*/
ngx_event_actions = ngx_epoll_mole_ctx.actions;
#if (NGX_HAVE_CLEAR_EVENT)
/*epoll將添加這個標志,主要為了實現邊緣觸發*/
ngx_event_flags = NGX_USE_CLEAR_EVENT
#else
/*水平觸發*/
ngx_event_flags = NGX_USE_LEVEL_EVENT
#endif
|NGX_USE_GREEDY_EVENT /*io的時候,直到EAGAIN為止*/
|NGX_USE_EPOLL_EVENT; /*epoll標志*/
return NGX_OK;
}

epoll初始化工作沒有想像中的復雜,和我們平時使用epoll都一樣,下面看ngx_epoll_process_events,這個函數主要用來完成事件的等待並處理。

[cpp] view plain print?
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
int events;
uint32_t revents;
ngx_int_t instance, i;
ngx_uint_t level;
ngx_err_t err;
ngx_log_t *log;
ngx_event_t *rev, *wev, **queue;
ngx_connection_t *c;
/*一開始就是等待事件,最長等待時間為timer;nginx為事件
專門用紅黑樹維護了一個計時器。後續對這個timer單獨分析。
*/
events = epoll_wait(ep, event_list, (int) nevents, timer);
if (events == -1) {
err = ngx_errno;
} else {
err = 0;
}
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
/*執行一次時間更新, nginx將時間緩存到了一組全局變數中,方便程序高效的獲取事件。*/
ngx_time_update();
}
/*處理wait錯誤*/
if (err) {
if (err == NGX_EINTR) {
if (ngx_event_timer_alarm) {
ngx_event_timer_alarm = 0;
return NGX_OK;
}
level = NGX_LOG_INFO;
} else {
level = NGX_LOG_ALERT;
}
ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
return NGX_ERROR;
}
/*wait返回事件數0,可能是timeout返回,也可能是非timeout返回;非timeout返回則是error*/
if (events == 0) {
if (timer != NGX_TIMER_INFINITE) {
return NGX_OK;
}
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"epoll_wait() returned no events without timeout");
return NGX_ERROR;
}
log = cycle->log;
/*for循環開始處理收到的所有事件*/
for (i = 0; i < events; i++) {

/*取得發生此事件的連接*/
c = event_list[i].data.ptr;
instance = (uintptr_t) c & 1;
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
/*獲得該連接上的讀事件*/
rev = c->read;
。。。。。。。。。。。。。

/*取得發生一個事件*/
revents = event_list[i].events;

/*記錄wait的錯誤返回狀態*/
if (revents & (EPOLLERR|EPOLLHUP)) {
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
"epoll_wait() error on fd:%d ev:%04XD",
c->fd, revents);
}
if ((revents & (EPOLLERR|EPOLLHUP))
&& (revents & (EPOLLIN|EPOLLOUT)) == 0)
{
/*
* if the error events were returned without EPOLLIN or EPOLLOUT,
* then add these flags to handle the events at least in one
* active handler
*/
revents |= EPOLLIN|EPOLLOUT;
}
/*該事件是一個讀事件,並該連接上注冊的讀事件是active的*/
if ((revents & EPOLLIN) && rev->active) {
if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
rev->posted_ready = 1;
} else {
rev->ready = 1;
}

/*事件放入相應的隊列中;關於此處的先入隊再處理,在前面的文章中已經介紹過了。*/
if (flags & NGX_POST_EVENTS) {
queue = (ngx_event_t **) (rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);
ngx_locked_post_event(rev, queue); /*入隊*/
} else {
rev->handler(rev);
}
}
wev = c->write;
/*發生的是一個寫事件,和讀事件完全一樣的邏輯過程*/
if ((revents & EPOLLOUT) && wev->active) {
if (flags & NGX_POST_THREAD_EVENTS) {
wev->posted_ready = 1;
} else {
wev->ready = 1;
}
/*先入隊再處理*/
if (flags & NGX_POST_EVENTS) {
ngx_locked_post_event(wev, &ngx_posted_events);
} else {
wev->handler(wev);
}
}
}
return NGX_OK;
}

本文將關注的兩個epoll函數也就這么一點代碼了,但整個epoll還有添加事件和刪除事件等的相關函數,代碼都很簡單,本文就不做具體的分析了。

寫到此處的時候,我感覺epoll模塊沒有分析的足夠詳細,或者說是沒有足夠的理解作者的用意,如果你有更好的理解,希望能夠告訴我。或許,隨著後面的分析,能夠逐漸的真正明白吧。

java學會那些知識找工作才不費力

很多Java初學者會關心這么一個問題——Java學到什麼程度就可以出去找工作了?大家的目標都很明確,也很實在,學習Java無非就是為了找個工作,使自己和家人生活更好。那到底要學到那些Java知識,就可以去找第一份工作了呢?

下面咱們就以公司大小運用到的技術來解答,為什麼這樣說呢,小型的公司肯定沒有大型公司運用到的知識多,從另一個角度來看,大家也可以來測試一下自我學到的知識符合去一個什麼樣的企業。下面是我給大家總結和介紹。

1、中小型公司:

這類公司可以說特別的多,招聘和培訓可能會有自己的一套標准,比如學歷上可能稍微做一些要求,技術上的把關也會有一定的方法,除了Java基礎知識和項目經歷之外,可能還會考查你的debug能力,代碼規范、異常處理能力,以及對一些Java高級特性的理解能力,可能最好多用過一些框架。

總而言之,這類公司選人的標准已經擁有了自我體系,不會像一些特別小的公司,招人很隨意,領導拍個板就行。當然,這類公司也吸引不到太多優秀人的人才,但是也確實可能會有一些踏實能乾的勤奮員工。

2、大中型公司:

這類公司一般都會要求本科學歷,對Java基礎知識要比較熟悉,最好能夠看過源碼,如果沒看過,那麼源碼方面的面試題好歹也要准備一下,除此之外,一般來說還會考察你的後端技術知識,比如資料庫、網路、操作系統,考察的不會太難,能把面經上的知識點掌握了就算是比較扎實了。

這類公司一般不會考太復雜的題目,更希望招一些水平能力都是中等的人才,只要知識面能比較廣,題目都能說到點子上,不需要掌握得特別深入,也可以有機會拿到offer。

其實歸結原因,就是因為二三線互聯網不太可能和一線公司爭奪一線人才,所以一般爭取的都是二線人才,不需要太優秀,但是至少要是中等水平,所以這些公司對很多程序員來說還是比較有機會的。

3、特大型公司:

要進這些公司,不僅要做到之前那些事情:掌握Java基礎、計算機基礎知識,並且是非常熟練地掌握,你需要深入理解每一個知識點,因為面試官會不斷深入地向你提問,了解你的知識深度,同時,你需要對源碼有所理解,在讀懂源碼的基礎上去理解框架的實現、JDK的實現。

另外,你需要對JVM有一個清晰的認識,不僅要了解其結構,垃圾回收原理,甚至還要知道如何在遇到線上問題時通過JVM調優來解決它們。

同理,你還需要對Java並發編程和網路編程的使用方法與底層實現原理非常熟悉,不僅僅答出NIO和BIO的區別,或者是synchronized和lock的區別,你還需要知道NIO的底層實現epoll是什麼,synchronized對應的mutex lock是什麼,lock和condition的實現原理又是什麼,而lock本身也是通過AQS、CAS操作類等組件來實現的,其中的內容實在太多,絕不只是幾道面試題就可以搞定的。

當然,除此之外,這些公司對資料庫、緩存、分布式技術等方面的要求都會比其他公司要高得多,你最好要搞懂MySQL的存儲引擎、索引和鎖的實現原理,Redis緩存的數據結構、備份方式、底層實現。同時如果你能理解負載均衡演算法、CAP理論,甚至是raft和paxos演算法,以及分布式常用技術如消息隊列、zookeeper等等,那麼無疑也是可以為你加分的技能。

為什麼大公司的要求這么高,因為它們是最好的互聯網公司,要招的自然也是最優秀的人才,如果考察底層原理還不能滿足他們篩選人才的需要,他們也會考察面試者的演算法能力,比如LeetCode上medium難度的原題,或者是劍指offer的變式題等等,演算法題相對考察理論基礎而言,篩選度更高,可以淘汰的人也更多。

③ 關於Linux下的select/epoll

select這個系統調用的原型如下

第一個參數nfds用來告訴內核 要掃描的socket fd的數量+1 ,select系統調用最大接收的數量是1024,但是如果每次都去掃描1024,實際上的數量並不多,則效率太低,這里可以指定需要掃描的數量。 最大數量為1024,如果需要修改這個數量,則需要重新編譯Linux內核源碼。
第2、3、4個參數分別是readfds、writefds、exceptfds,傳遞的參數應該是fd_set 類型的引用,內核會檢測每個socket的fd, 如果沒有讀事件,就將對應的fd從第二個參數傳入的fd_set中移除,如果沒有寫事件,就將對應的fd從第二個參數的fd_set中移除,如果沒有異常事件,就將對應的fd從第三個參數的fd_set中移除 。這里我們應該 要將實際的readfds、writefds、exceptfds拷貝一份副本傳進去,而不是傳入原引用,因為如果傳遞的是原引用,某些socket可能就已經丟失
最後一個參數是等待時間, 傳入0表示非阻塞,傳入>0表示等待一定時間,傳入NULL表示阻塞,直到等到某個socket就緒

FD_ZERO()這個函數將fd_set中的所有bit清0,一般用來進行初始化等。
FD_CLR()這個函數用來將bitmap(fd_set )中的某個bit清0,在客戶端異常退出時就會用到這個函數,將fd從fd_set中刪除。
FD_ISSET()用來判斷某個bit是否被置1了,也就是判斷某個fd是否在fd_set中。
FD_SET()這個函數用來將某個fd加入fd_set中,當客戶端新加入連接時就會使用到這個函數。

epoll_create系統調用用來創建epfd,會在開辟一塊內存空間(epoll的結構空間)。size為epoll上能關注的最大描述符數,不夠會進行擴展,size只要>0就行,早期的設計size是固定大小,但是現在size參數沒什麼用,會自動擴展。
返回值是epfd,如果為-1則說明創建epoll對象失敗

第一個參數epfd傳入的就是epoll_create返回的epfd。
第二個參數傳入對應操作的宏,包括 增刪改(EPOLL_CTL_ADD、EPOLL_CTL_DEL、EPOLL_CTL_MOD)
第三個參數傳入的是 需要增刪改的socket的fd
第四個參數傳入的是 需要操作的fd的哪些事件 ,具體的事件可以看後續。
返回值是一個int類型,如果為-1則說明操作失敗

第一個參數是epfd,也就是epoll_create的返回值。
第二個參數是一個epoll_event類型的指針,也就是傳入的是一個數組指針。 內核會將就緒的socket的事件拷貝到這個數組中,用戶可以根據這個數組拿到事件和消息等
第三個參數是maxevents,傳入的是 第二個參數的數組的容量
第四個參數是timeout, 如果設為-1一直阻塞直到有就緒數據為止,如果設為0立即返回,如果>0那麼阻塞一段時間
返回值是一個int類型,也就是就緒的socket的事件的數量(內核拷貝給用戶的events的元素的數量),通過這個數量可以進行遍歷處理每個事件

一般需要傳入 ev.data.fd 和 ev.events ,也就是fd和需要監控的fd的事件。事件如果需要傳入多個,可以通過按位與來連接,比如需要監控讀寫事件,只需要像如下這樣操作即可: ev.events=EPOLLIN | EPOLLOUT 。

LT(水平觸發), 默認 的工作模式, 事件就緒後用戶可以選擇處理和不處理,如果用戶不處理,內核會對這部分數據進行維護,那麼下次調用epoll_wait()時仍舊會打包出來
ET(邊緣觸發),事件就緒之後, 用戶必須進行處理 ,因為內核把事件打包出來之後就把對應的就緒事件給清掉了, 如果不處理那麼就緒事件就沒了 。ET可以減少epoll事件被重復觸發的次數,效率比LT高。
如果需要設置為邊緣觸發只需要設置事件為類似 ev.events=EPOLLIN | EPOLLET 即可

select/poll/epoll是nio多路復用技術, 傳統的bio無法實現C10K/C100K ,也就是無法滿足1w/10w的並發量,在這么高的並發量下,在進行上下文切換就很容易將伺服器的負載拉飛。

1.將fd_set從用戶態拷貝到內核態
2.根據fd_set掃描內存中的socket的fd的狀態,時間復雜度為O(n)
3.檢查fd_set,如果有已經就緒的socket,就給對應的socket的fd打標記,那麼就return 就緒socket的數量並喚醒當前線程,如果沒有就緒的socket就繼續阻塞當前線程直到有socket就緒才將當前線程喚醒。
4.如果想要獲取當前已經就緒的socket列表,則還需要進行一次系統調用,使用O(n)的時間去掃描socket的fd列表,將已經打上標記的socket的fd返回。

CPU在同一個時刻只能執行一個程序,通過RR時間片輪轉去切換執行各個程序。沒有被掛起的進程(線程)則在工作隊列中排隊等待CPU的執行,將進程(線程)從工作隊列中移除就是掛起,反映到Java層面的就是線程的阻塞。

什麼是中斷?當我們使用鍵盤、滑鼠等IO設備的時候,會給主板一個電流信號,這個電流信號就給CPU一個中斷信號,CPU執行完當前的指令便會保存現場,然後執行鍵盤/滑鼠等設備的中斷程序,讓中斷程序獲取CPU的使用權,在中斷程序後又將現場恢復,繼續執行之前的進程。

如果第一次沒檢測到就緒的socket,就要將其進程(線程)從工作隊列中移除,並加入到socket的等待隊列中。

socket包含讀緩沖區+寫緩沖區+等待隊列(放線程或eventpoll對象)

當從客戶端往伺服器端發送數據時,使用TCP/IP協議將通過物理鏈路、網線發給伺服器的網卡設備,網卡的DMA設備將接收到的的數據寫入到內存中的一塊區域(網卡緩沖區),然後會給CPU發出一個中斷信號,CPU執行完當前指令則會保存現場,然後網卡的中斷程序就獲得了CPU的使用權,然後CPU便開始執行網卡的中斷程序,將內存中的緩存區中的數據包拿出,判斷埠號便可以判斷它是哪個socket的數據,將數據包寫入對應的socket的讀(輸入)緩沖區,去檢查對應的socket的等待隊列有沒有等待著的進程(線程),如果有就將該線程(進程)從socket的等待隊列中移除,將其加入工作隊列,這時候該進程(線程)就再次擁有了CPU的使用許可權,到這里中斷程序就結束了。

之後這個進程(線程)就執行select函數再次去檢查fd_set就能發現有socket緩沖區中有數據了,就將該socket的fd打標記,這個時候select函數就執行完了,這時候就會給上層返回一個int類型的數值,表示已經就緒的socket的數量或者是發生了錯誤。這個時候就再進行內核態到用戶態的切換,對已經打標記的socket的fd進行處理。

將原本1024bit長度的bitmap(fd_set)換成了數組的方式傳入 ,可以 解決原本1024個不夠用的情況 ,因為傳入的是數組,長度可以不止是1024了,因此socket數量可以更多,在Kernel底層會將數組轉換成鏈表。

在十多年前,linux2.6之前,不支持epoll,當時可能會選擇用Windows/Unix用作伺服器,而不會去選擇Linux,因為select/poll會隨著並發量的上升,性能變得越來越低,每次都得檢查所有的Socket列表。

1.select/poll每次調用都必須根據提供所有的socket集合,然後就 會涉及到將這個集合從用戶空間拷貝到內核空間,在這個過程中很耗費性能 。但是 其實每次的socket集合的變化也許並不大,也許就1-2個socket ,但是它會全部進行拷貝,全部進行遍歷一一判斷是否就緒。

2.select/poll的返回類型是int,只能代表當前的就緒的socket的數量/發生了錯誤, 如果還需要知道是哪些socket就緒了,則還需要再次使用系統調用去檢查哪些socket是就緒的,又是一次O(n)的操作,很耗費性能

1.epoll在Kernel內核中存儲了對應的數據結構(eventpoll)。我們可以 使用epoll_create()這個系統調用去創建一個eventpoll對象 ,並返回eventpoll的對象id(epfd),eventpoll對象主要包括三個部分:需要處理的正在監聽的socket_fd列表(紅黑樹結構)、socket就緒列表以及等待隊列(線程)。

2.我們可以使用epoll_ctl()這個系統調用對socket_fd列表進行CRUD操作,因為可能頻繁地進行CRUD,因此 socket_fd使用的是紅黑樹的結構 ,讓其效率能更高。epoll_ctl()傳遞的參數主要是epfd(eventpoll對象id)。

3.epoll_wait()這個系統調用默認會 將當前進程(線程)阻塞,加入到eventpoll對象的等待隊列中,直到socket就緒列表中有socket,才會將該進程(線程)重新加入工作隊列 ,並返回就緒隊列中的socket的數量。

socket包含讀緩沖區、寫緩沖區和等待隊列。當使用epoll_ctl()系統調用將socket新加入socket_fd列表時,就會將eventpoll對象引用加到socket的等待隊列中, 當網卡的中斷程序發現socket的等待隊列中不是一個進程(線程),而是一個eventpoll對象的引用,就將socket引用追加到eventpoll對象的就緒列表的尾部 。而eventpoll對象中的等待隊列存放的就是調用了epoll_wait()的進程(線程),網卡的中斷程序執行會將等待隊列中的進程(線程)重新加入工作隊列,讓其擁有佔用CPU執行的資格。epoll_wait()的返回值是int類型,返回的是就緒的socket的數量/發生錯誤,-1表示發生錯誤。

epoll的參數有傳入一個epoll_event的數組指針(作為輸出參數),在調用epoll_wait()返回的同時,Kernel內核還會將就緒的socket列表添加到epoll_event類型的數組當中。

④ Redis和Memcached的區別

Redis的作者Salvatore Sanfilippo曾經對這兩種基於內存的數據存儲系統進行過比較:


1、Redis支持伺服器端的數據操作:Redis相比Memcached來說,擁有更多的數據結構和並支持更豐富的數據操作,通常在Memcached里,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網路IO的次數和數據體積。在Redis中,這些復雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能夠支持更復雜的結構和操作,那麼Redis會是不錯的選擇。


2、內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高,而如果Redis採用hash結構來做key-value存儲,由於其組合式的壓縮,其內存利用率會高於Memcached。


3、性能對比:由於Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還是稍有遜色。


具體為什麼會出現上面的結論,以下為收集到的資料:


1、數據類型支持不同


與Memcached僅支持簡單的key-value結構的數據記錄不同,Redis支持的數據類型要豐富得多。最為常用的數據類型主要由五種:String、Hash、List、Set和Sorted Set。Redis內部使用一個redisObject對象來表示所有的key和value。redisObject最主要的信息如圖所示:




type代表一個value對象具體是何種數據類型,encoding是不同數據類型在redis內部的存儲方式,比如:type=string代表value存儲的是一個普通字元串,那麼對應的encoding可以是raw或者是int,如果是int則代表實際redis內部是按數值型類存儲和表示這個字元串的,當然前提是這個字元串本身可以用數值表示,比如:」123″ 「456」這樣的字元串。只有打開了Redis的虛擬內存功能,vm欄位欄位才會真正的分配內存,該功能默認是關閉狀態的。


1)String


⑤ 程序員打基礎必看書籍!

1、《深入理解計算機系統》
從c語言到匯編語言到硬體再到操作系統,寫得非常好。是一本能幫助深入理解計算機系統的書。基本上把這本書吃透面試操作系統的大部分問題都不是問題。
2、《演算法導論(第三版)》
被很多acmer coder奉為學演算法的經典之作,但不太適合初學者,因為它這本書很多內容只提供了偽代碼,而沒有具體實現。但可以從這本書學數據結構和演算法好,因為日後的編程語言對實現而言實際上並沒有特別大的障礙,只是適合與不適合的選擇罷了,而把想法轉換成編程語言才是對演算法知識的考驗。如果不想太過深入的話可以忽略掉第四部分(高級設計和分析技術)第五部分(高級數據結構)和第七部分(演算法問題選編),你會發現書其實比你想像中薄很多噢!
3、《計算機網路:自頂向下方法》
軟體學院的計算機網路教材,非常適合初學者,裡面將計算機網路從頂層到底層逐章分析了一遍,如果能夠結合一些實驗來輔助理解會更好,因為裡面的講解比較抽象。
4、《STL源碼剖析》
如果你是經常用c++刷演算法題的同學,那麼一定經常用STL的各種集合, vector, set, stack, queue等等。它們的實現原理,在源碼面前,完全沒有秘密。
5、《圖解HTTP》
日本人著的介紹HTTP協議的書,對理解HTTP協議的一些細節有非常大的幫助,插畫也很多,感覺就像看漫畫一樣,很容易理解的。
6、《TCP/IP詳解卷一》
這本書能把枯燥的知識講得很細致,強烈推薦這本,看完相應章節後大概能夠明白為什麼TCP/IP要這么設計了。面試的時候經常問到三次握手和四次揮手,還有各種狀態的轉移, TIME_WAIT的時間為什麼是2*MSL······
7、《UNIX網路編程卷一:套接字聯網API(第三版)》
中文版快800頁,不過我只看了一些章節,這本書也是把TCP/IP的細節講得很深很深,此外還有非常重要的基本套接字編程,就是寫網路程序的時候那些bind, accept, listen, send, receive函數之類的,內容非常多,但是這些是理解多路復用模型所需要掌握的······select/poll/epoll這些系統調用解決了什麼問題?事件機制能不能理解?就看這本書的前六章了。
8、《資料庫管理系統(原理與設計)》
這個也是web開發中離不開的東西,必須劃重點學會的是ER圖/SQL語句/存儲數據(磁碟|文件|RAID|緩沖池等)/三大範式/索引以及相應的數據結構/事務相關的所有概念,尤其重點學習SQL 。之後學會使用mysql workbench來進行資料庫建模/逆向工程生成建表語句/根據SQL生成JAVA實體類等就不贅述了,開發過程中網路谷歌一下就知道啦,然後如果習慣在windows下開發的同學推薦利用navicat這個好東西。

⑥ 為什麼epoll里的read函數每次都只能讀一小片數據

Linux平台上,Nginx使用epoll完成事件驅動,實現高並發;本文將不對epoll本身進行介紹(網上一堆一堆的文章介紹epoll的原理及使用方法,甚至源碼分析等),僅看一下Nginx是如何使用epoll的。 Nginx在epoll模塊中定義了好幾個函

⑦ linux epoll源碼哪個包

#include #include /* basic system data types */#include /* basic socket definitions */#include /* sockaddr_in{} and other Internet defns */#include /* inet(3) functions */#include /* epoll function */#include /* nonblocking */#...

⑧ .nginx第一次的啟動的時候會創建哪些文件

nginx是個多進程web容器,不同的配置下它的啟動方式也是不同的,這里我只說說最典型的啟動方式。
它有1個master進程,和多個worker進程(最優配置的數量與CPU核數相關)。那麼,首先我們要找到main函數,它在src/core/nginx.c文件中。談到源碼了,這時我們先簡單看下源碼的目錄結構吧。
nginx主要有下列目錄:
src/core,這個目錄存放了基礎的數據結構像LIST、紅黑樹、nginx字元串,貫穿始終的一些邏輯結構如ngx_cycle_s、ngx_connection_s等,還有對一些底層操作的封裝如log、文件操作、共享內存、內存池等,最後還有個nginx.c這個main啟動函數了。
src/event,這個目錄下存放與抽象事件相關的結構和鉤子函數。nginx是以事件驅動處理流程的,事件自然是整個體系的核心了,這里定義了最核心的ngx_event_s結構。
src/event/moles目錄存放了具體的種種事件驅動方式,例如epoll、kqueue、poll、aio、select等,它們通過ngx_event_actions_t結構體中的鉤子掛在nginx中。nginx啟動時會根據配置來決定使用哪種實現方式。
src/os/unix中存放了unix系統下許多函數調用的UNIX實現。
src/http目錄存放到http mole的相關實現,這個mole負責處理http請求,包括協議的解析以及訪問backend server的代碼。
src/http/mole目錄存放http mole類型的一些特定用途的mole,比如gzip處理加密,圖片壓縮等。
有個初步了解後,回到main函數中,順序看看我們感興趣的事情。它先執行了ngx_time_init,為什麼要初始化時間呢?nginx考慮的還是很周到的,取系統時間gettimeofday是系統調用,這意味著,需要發送中斷給linux內核,內核需要做進程間切換來處理這個調用。這是一個不能忽視成本的函數。nginx封裝了時間函數,這樣,每次我們需要處理時間時,並不是調用gettimeofday,而是nginx自己緩存的時間,這樣大量減少了系統調用,取當前時間這事可是誰都愛乾的。
那麼,nginx是怎麼維護自己的這個時鍾呢?如何保證用戶取到的當前時間是有意義的?nginx設計者的出發點是,nginx是事件驅動機制,當一批事件發生時,也就是epoll_wait返回時,會取一次gettimeofday來更新自己的時間,然後調用各個事件對應的處理函數。這些函數都會保證自己是無阻塞的,也就是毫秒級的處理能力,所以,在任何一個事件處理函數中,取到的時間都是之前epoll_wait剛返回時取到的時間,這樣,即使拿到的時間慢了幾毫秒也無所謂。關鍵是,每個函數都是無阻塞的,都要迅速的把控制權交還給nginx,這是基本設計原則哈。

⑨ java自學到什麼程度就能找工作了

很多同學都關心Java學到什麼程度才可以找到滿意的工作。大家的目標都很明確,也很實在,學習Java無非就是為了找工作。

那到底要學多少Java知識,掌握多少技能,才可以找到一份滿意的工作呢?

其實想要找一份小公司的開發工作不算非常難,畢竟互聯網公司很多,要求也是天差地別,對技術、學歷、實踐能力的要求和評價標准也有很大的差距。但是進大廠的要求可就非常高了。

所以,到底Java學到什麼程度才能找到第一份工作,我想應該用公司來作為變數,這樣回答這個問題才有意義。

1、中小型公司

說到中小型公司,我們泛指那些500名以下員工,有穩定資金來源並且可以自我造血的公司,這類公司招聘和培訓可能會有自己的一套標准。

比如學歷上可能稍微做一些要求,技術上的把關更嚴格一點,除了Java基礎知識和項目經歷之外,可能還會考查你的debug能力,代碼規范、異常處理能力,以及對一些Java高級特性的理解能力,以及框架的應用水平。

總而言之,這類公司選人的標准更加有體系,標准也更高。

2、二三線互聯網公司

這類公司范圍就很廣了,比如搜狐、新浪、360、攜程這類現狀比較不錯的企業等等,這類公司擠不到BAT TMD等一線互聯網行列,但是在二三線陣容還算是比較不錯的公司,它們對於人才的要求其實還是相對比較高的。

比如一般都會要求本科學歷,對Java基礎知識要比較熟悉,最好能夠看過源碼,如果沒看過,那麼源碼方面的面試題好歹也要准備一下,除此之外,一般來說還會考察你的後端技術知識,比如資料庫、網路、操作系統,考察的不會太難,能把面經上的知識點掌握了就算是比較扎實了。

這類公司一般不會考太復雜的題目,更希望招一些水平能力都是中上等的人才,只要知識面能比較廣,題目都能說到點子上,也可以有機會拿到offer。

3、一線互聯網公司

BAT、TMD等互聯網名企都屬於這類公司,這類公司和二三線互聯網公司的發展差距還是比較大的,體現在公司的規模、市值、甚至是股價等方面,業務以技術為基礎,因此這些公司的技術往往也是業界最頂尖的,比如阿里的雲計算和中間件,頭條的推薦演算法、騰訊的游戲技術等等。

要進這些公司,不僅要做到之前那些事情:掌握Java基礎、計算機基礎知識,並且是非常熟練地掌握,你需要深入理解每一個知識點,因為面試官會不斷深入地向你提問,了解你的知識深度,同時,你需要對源碼有所理解,在讀懂源碼的基礎上去理解框架的實現、JDK的實現。

並且,你還需要對Java並發編程和網路編程的使用方法與底層實現原理非常熟悉,不僅僅答出NIO和BIO的區別,或者是synchronized和lock的區別,你還需要知道NIO的底層實現epoll是什麼,synchronized對應的mutex lock是什麼,lock和condition的實現原理又是什麼,而lock本身也是通過AQS、CAS操作類等組件來實現的,其中的內容實在太多,絕不只是幾道面試題就可以搞定的。

當然,除此之外,這些公司對資料庫、緩存、分布式技術等方面的要求都會比其他公司要高得多,你最好要搞懂MySQL的存儲引擎、索引和鎖的實現原理,Redis緩存的數據結構、備份方式、底層實現。

同時如果你能理解負載均衡演算法、CAP理論,甚至是raft和paxos演算法,以及分布式常用技術如消息隊列、zookeeper等等,那麼無疑也是可以為你加分的技能。

分享下學習路線,按照上面的路線學習,學完後找到工作不成問題!

世上無難事,只怕有心人,只要你真的想學並努力去學,你就能成功。

另外,如果自學沒有資料的話,可私聊我獲取,免費提供哦~

希望能幫到你,望採納!

閱讀全文

與epoll源碼原理相關的資料

熱點內容
自己購買雲主伺服器推薦 瀏覽:419
個人所得稅java 瀏覽:761
多餘的伺服器滑道還有什麼用 瀏覽:189
pdf劈開合並 瀏覽:27
不能修改的pdf 瀏覽:750
同城公眾源碼 瀏覽:488
一個伺服器2個埠怎麼映射 瀏覽:297
java字元串ascii碼 瀏覽:78
台灣雲伺服器怎麼租伺服器 瀏覽:475
旅遊手機網站源碼 瀏覽:332
android關聯表 瀏覽:945
安卓導航無聲音怎麼維修 瀏覽:332
app怎麼裝視頻 瀏覽:430
安卓系統下的軟體怎麼移到桌面 瀏覽:96
windows拷貝到linux 瀏覽:772
mdr軟體解壓和別人不一樣 瀏覽:904
單片機串列通信有什麼好處 瀏覽:340
游戲開發程序員書籍 瀏覽:860
pdf中圖片修改 瀏覽:288
匯編編譯後 瀏覽:491