• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

            The libevent API provides a mechanism to execute a callback function when a
            specific event occurs on a file descriptor or after a timeout has been
            reached. Furthermore, libevent also support callbacks due to signals or
            regular timeouts.

            libevent is meant to replace the event loop found in event driven network
            servers. An application just needs to call event_dispatch() and then add or
            remove events dynamically without having to change the event loop.


            官網
            http://libevent.org/

            Fast portable non-blocking network programming with Libevent
            http://www.wangafu.net/~nickm/libevent-book/


            epoll學習筆記
            http://m.shnenglu.com/converse/archive/2008/04/29/48482.aspx

            libevent事件處理框架分析
            http://m.shnenglu.com/converse/archive/2009/01/03/71040.aspx

            libevent入門教程:Echo Server based on libevent
            http://www.felix021.com/blog/read.php?2068

            libevent源碼深度剖析
            http://blog.csdn.net/sparkliang/article/category/660506

            libevent源碼分析
            How to use epoll? A complete example in C

            https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

            posted @ 2013-01-17 17:34 鑫龍 閱讀(5040) | 評論 (0)編輯 收藏

                 摘要: 一.多線程  1.了解多線程    解決多任務實現。    歷史上Unix服務器不支持多線程    Unix/Linux上實現多線程有兩種方式:     內核支持多線程   &nb...  閱讀全文

            posted @ 2013-01-17 14:30 鑫龍 閱讀(671) | 評論 (0)編輯 收藏

            Reactor這個詞譯成漢語還真沒有什么合適的,很多地方叫反應器模式,但更多好像就直接叫reactor模式了,其實我覺著叫應答者模式更好理解一些。通過了解,這個模式更像一個侍衛,一直在等待你的召喚,或者叫召喚獸。

             

            并發系統常使用reactor模式,代替常用的多線程的處理方式,節省系統的資源,提高系統的吞吐量。

             

            先用比較直觀的方式來介紹一下這種方式的優點,通過和常用的多線程方式比較一下,可能更好理解。

            以一個餐飲為例,每一個人來就餐就是一個事件,他會先看一下菜單,然后點餐。就像一個網站會有很多的請求,要求服務器做一些事情。處理這些就餐事件的就需要我們的服務人員了。

             

            在多線程處理的方式會是這樣的:

            一個人來就餐,一個服務員去服務,然后客人會看菜單,點菜。 服務員將菜單給后廚。

            二個人來就餐,二個服務員去服務……

            五個人來就餐,五個服務員去服務……

             

            這個就是多線程的處理方式,一個事件到來,就會有一個線程服務。很顯然這種方式在人少的情況下會有很好的用戶體驗,每個客人都感覺自己是VIP,專人服務的。如果餐廳一直這樣同一時間最多來5個客人,這家餐廳是可以很好的服務下去的。

             

            來了一個好消息,因為這家店的服務好,吃飯的人多了起來。同一時間會來10個客人,老板很開心,但是只有5個服務員,這樣就不能一對一服務了,有些客人就要沒有人管了。老板就又請了5個服務員,現在好了,又能每個人都受VIP待遇了。

             

            越來越多的人對這家餐廳滿意,客源又多了,同時來吃飯的人到了20人,老板高興不起來了,再請服務員吧,占地方不說,還要開工錢,再請人就攢不到錢了。怎么辦呢?老板想了想,10個服務員對付20個客人也是能對付過來的,服務員勤快點就好了,伺候完一個客人馬上伺候另外一個,還是來得及的。綜合考慮了一下,老板決定就使用10個服務人員的線程池啦~~~

             

            但是這樣有一個比較嚴重的缺點就是,如果正在接受服務員服務的客人點菜很慢,其他的客人可能就要等好長時間了。有些火爆脾氣的客人可能就等不了走人了。

             

            Reactor如何處理這個問題呢:

            老板后來發現,客人點菜比較慢,大部服務員都在等著客人點菜,其實干的活不是太多。老板能當老板當然有點不一樣的地方,終于發現了一個新的方法,那就是:當客人點菜的時候,服務員就可以去招呼其他客人了,等客人點好了菜,直接招呼一聲“服務員”,馬上就有個服務員過去服務。嘿嘿,然后在老板有了這個新的方法之后,就進行了一次裁員,只留了一個服務員!這就是用單個線程來做多線程的事。

             

            實際的餐館都是用的Reactor模式在服務。一些設計的模型其實都是從生活中來的。

             

            Reactor模式主要是提高系統的吞吐量,在有限的資源下處理更多的事情。

             

            在單核的機上,多線程并不能提高系統的性能,除非在有一些阻塞的情況發生。否則線程切換的開銷會使處理的速度變慢。就像你一個人做兩件事情,1、削一個蘋果。2、切一個西瓜。那你可以一件一件的做,我想你也會一件一件的做。如果這個時候你使用多線程,一會兒削蘋果,一會切西瓜,可以相像究竟是哪個速度快。這也就是說為什么在單核機上多線程來處理可能會更慢。

             

            但當有阻礙操作發生時,多線程的優勢才會顯示出來,現在你有另外兩件事情去做,1、削一個蘋果。2、燒一壺開水。我想沒有人會去做完一件再做另一件,你肯定會一邊燒水,一邊就把蘋果削了。

             


            轉自:http://daimojingdeyu.iteye.com/blog/828696

            posted @ 2013-01-17 13:38 鑫龍 閱讀(505) | 評論 (0)編輯 收藏

                 摘要: 轉自:http://my.oschina.net/tuzibuluo/blog?catalog=1278261.Writable接口         Hadoop 并沒有使用 JAVA 的序列化,而是引入了自己實的序列化系統, package org.apache.hadoop.io 這個...  閱讀全文

            posted @ 2013-01-15 21:48 鑫龍 閱讀(1131) | 評論 (0)編輯 收藏

                 轉載請注明 出自:http://m.shnenglu.com/mysileng/archive/2013/01/15/197284.html

                 今天在看UNP6.5節,學習到了select與stdio混用的后果。特此進程實驗一番。再實驗之前需明確一下幾點:
            1.stdio流的i/o函數 與 系統i/o函數不同。stdio流函數在用戶空間和內核都有緩沖,系統i/o函數只在內核有緩沖,用戶空間沒有。

            2.stdio流的i/o函數緩沖機制:在面對文件時候用的是全緩沖,面對設備的時候用的行緩沖。(等下試驗用的是鍵盤和屏幕),所以實驗用的stdio函數采用行行緩沖。

            3.select函數對于某一個描述符是否準備好可讀可寫,是對內核緩沖區中的數據是否達到某一個最低標準,而不是用戶緩沖區。也就是說select函數不知道用戶緩沖區的存在。

            首先寫了一個系統i/o函數 簡單的select函數程序:

                 程序給select函數只設置的鍵盤的描述符。也就是說如果鍵盤的描述符準備好了就不再阻塞。但是這里有一個問題,解除阻塞后,我們最多只從內核緩沖區讀3個字節,這個時候就會有兩個情況:
            (1)內核空間本來存儲的數據就小于等于3個字節,全被讀走。那下次再次調用select函數,應該肯定會阻塞的,因為鍵盤輸入的內核緩沖區已經沒有數據了。
            情況如下(內核空間只有3個字節:1 2 \n):


            (2)如果內核空間的數據多余3個字節,但是因為最多只能讀3個字節,就必將導致內核中有數據讀不完。那么下次再遇到select函數的時候是否會阻塞呢?
            情況見下:

                 當我們輸入5個字符時候(1 2 3 4 \n),第一次read掉3個字符,內核空間還剩下2個字符,然后再次碰到select函數,默認情況下如果鍵盤內核空間字符數大于1,select是不會阻塞鍵盤描述符的。結果也印證了,又read了2個字節,并沒有堵塞。
                  綜上所述select是可以看見內核空間的緩沖區的。那到底能不能看見用戶空間緩沖區呢?我們換成stdio流的i/o函數繼續實驗。

            --------------------------------------------------------------------
            stdio流的i/o函數使用select函數的程序如下:


            程序用stdio流的getc函數從鍵盤讀數據,運行結果如下:

               我們輸入5個字符(1 2 3 4 \n),結果只輸出了1個字符,然后就阻塞了。我們分析一下,首先輸入5個字符,這5個字符被放入用戶緩沖區,因為最后一個是換行符并且stdio面對設備使用行緩沖機制,所以這5個字符馬上接著被從用戶緩沖區刷入內核緩沖區。然后調用select函數,select函數發現內核空間中有數據,于是不阻塞返回。接著getc函數從用戶空間輸出緩沖區取一個字符,因為用戶空間輸出緩沖區沒有數據,于是把內核空間的數據調入一行給用戶空間輸出緩沖區,然后getc返回。接著又碰上select函數,因為內核緩沖空間的數據已經被放入用戶空間輸出緩沖區了,所以內核緩沖沒有數據,那么select認為鍵盤沒有準備好,所以阻塞。雖然阻塞了,但需要注意的時候這個時候,用戶空間是有4個字符數據的,被select函數無視了。

                 接下來假設我們再輸入2個字符(1 \n),將會發生什么呢?

                輸出一對東西,這是怎么回事,我們繼續分析。當輸入2個字符(1 \n)的時候,內核空間緩沖沒有數據,用戶空間輸出緩沖有4個字符。2個字符根據上一段同樣原理,被刷入內核空間緩沖區。select函數被調用,發現有2個字符,于是不阻塞返回。getc函數從用戶輸出緩沖取出一個字符,打印stardard... --2然后返回。再次循環,調用select函數。關鍵來了,這里跟上次不一樣了。這個時候內核空間的緩沖中還有上次遺留的2個字符,所以依然不阻塞返回,調用getc函數繼續打印。。。這里的關鍵是,getc函數。getc函數在用戶輸出緩沖中有數據的時候,不會把內核空間緩沖中的數據移入用戶空間的輸出緩沖,使得內核空間緩沖一直留有數據。這將會持續到用戶空間輸出緩沖的數據被取完為止。所以上述奇怪的打印結果就可以解釋的了。
            綜上所述,select函數確實是看不見用戶空間緩沖的尋在的。


            所以如果在使用select函數的時候,要謹慎使用stdio流函數。

            posted @ 2013-01-15 13:09 鑫龍 閱讀(992) | 評論 (1)編輯 收藏

            功能描述:根據文件描述詞來操作文件的特性。

            #include <unistd.h>
            #include <fcntl.h> 
            int fcntl(int fd, int cmd); 
            int fcntl(int fd, int cmd, long arg); 
            int fcntl(int fd, int cmd, struct flock *lock);

            [描述]
            fcntl()針對(文件)描述符提供控制。參數fd是被參數cmd操作(如下面的描述)的描述符。針對cmd的值,fcntl能夠接受第三個參數int arg。

            [返回值]
            fcntl()的返回值與命令有關。如果出錯,所有命令都返回-1,如果成功則返回某個其他值。下列三個命令有特定返回值:F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN。
                F_DUPFD   返回新的文件描述符
                F_GETFD   返回相應標志
                F_GETFL , F_GETOWN   返回一個正的進程ID或負的進程組ID

             

            fcntl函數有5種功能: 
            1. 復制一個現有的描述符(cmd=F_DUPFD). 
            2. 獲得/設置文件描述符標記(cmd=F_GETFD或F_SETFD). 
            3. 獲得/設置文件狀態標記(cmd=F_GETFL或F_SETFL). 
            4. 獲得/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN). 
            5. 獲得/設置記錄鎖(cmd=F_GETLK , F_SETLK或F_SETLKW).

            1. cmd值的F_DUPFD : 
            F_DUPFD    返回一個如下描述的(文件)描述符:
                    ·最小的大于或等于arg的一個可用的描述符
                    ·與原始操作符一樣的某對象的引用
                    ·如果對象是文件(file)的話,則返回一個新的描述符,這個描述符與arg共享相同的偏移量(offset)
                    ·相同的訪問模式(讀,寫或讀/寫)
                    ·相同的文件狀態標志(如:兩個文件描述符共享相同的狀態標志)
                    ·與新的文件描述符結合在一起的close-on-exec標志被設置成交叉式訪問execve(2)的系統調用

            實際上調用dup(oldfd);
            等效于
                    fcntl(oldfd, F_DUPFD, 0);

            而調用dup2(oldfd, newfd);
            等效于
                    close(oldfd);
                    fcntl(oldfd, F_DUPFD, newfd);

            2. cmd值的F_GETFD和F_SETFD:      
            F_GETFD    取得與文件描述符fd聯合的close-on-exec標志,類似FD_CLOEXEC。如果返回值和FD_CLOEXEC進行與運算結果是0的話,文件保持交叉式訪問exec(),否則如果通過exec運行的話,文件將被關閉(arg 被忽略)        
            F_SETFD    設置close-on-exec標志,該標志以參數arg的FD_CLOEXEC位決定,應當了解很多現存的涉及文件描述符標志的程序并不使用常數 FD_CLOEXEC,而是將此標志設置為0(系統默認,在exec時不關閉)或1(在exec時關閉)    

            在修改文件描述符標志或文件狀態標志時必須謹慎,先要取得現在的標志值,然后按照希望修改它,最后設置新標志值。不能只是執行F_SETFD或F_SETFL命令,這樣會關閉以前設置的標志位。 

            3. cmd值的F_GETFL和F_SETFL:   
            F_GETFL    取得fd的文件狀態標志,如同下面的描述一樣(arg被忽略),在說明open函數時,已說明
            了文件狀態標志。不幸的是,三個存取方式標志 (O_RDONLY , O_WRONLY , 以及O_RDWR)并不各占1位。(這三種標志的值各是0 , 1和2,由于歷史原因,這三種值互斥 — 一個文件只能有這三種值之一。) 因此首先必須用屏蔽字O_ACCMODE相與取得存取方式位,然后將結果與這三種值相比較。       
            F_SETFL    設置給arg描述符狀態標志,可以更改的幾個標志是:O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC。而fcntl的文件狀態標志總共有7個:O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC

            可更改的幾個標志如下面的描述:
                O_NONBLOCK   非阻塞I/O,如果read(2)調用沒有可讀取的數據,或者如果write(2)操作將阻塞,則read或write調用將返回-1和EAGAIN錯誤
                O_APPEND     強制每次寫(write)操作都添加在文件大的末尾,相當于open(2)的O_APPEND標志
                O_DIRECT     最小化或去掉reading和writing的緩存影響。系統將企圖避免緩存你的讀或寫的數據。如果不能夠避免緩存,那么它將最小化已經被緩存了的數據造成的影響。如果這個標志用的不夠好,將大大的降低性能
                O_ASYNC      當I/O可用的時候,允許SIGIO信號發送到進程組,例如:當有數據可以讀的時候

            轉載自:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201010265577965/
            1、獲取文件的flags,即open函數的第二個參數:
                   flags = fcntl(fd,F_GETFL,0);

            2、設置文件的flags:

                  fcntl(fd,F_SETFL,flags);

            3、增加文件的某個flags,比如文件是阻塞的,想設置成 非阻塞:

                   flags = fcntl(fd,F_GETFL,0);

                   flags |= O_NONBLOCK;

                  fcntl(fd,F_SETFL,flags);

            4、取消文件的某個flags,比如文件是非阻塞的,想設置 成為阻塞:

                  flags = fcntl(fd,F_GETFL,0);

                  flags &= ~O_NONBLOCK;

                  fcntl(fd,F_SETFL,flags);

             

            獲取和設置文件flags舉例::

            #include <stdio.h>
            #include <stdlib.h>
            #include <unistd.h>
            #include <fcntl.h>
            #include <error.h>

            char buf[500000];

            int main(int argc,char *argv[])
            {
                    int ntowrite,nwrite;
                    const char *ptr ;
                    int flags;
                
                    ntowrite = read(STDIN_FILENO,buf,sizeof(buf));
                    if(ntowrite <0) 
                    {   
                            perror("read STDIN_FILENO fail:");
                            exit(1);
                    }   
                    fprintf(stderr,"read %d bytes\n",ntowrite);
                
                    if((flags = fcntl(STDOUT_FILENO,F_GETFL,0))==-1)
                    {   
                            perror("fcntl F_GETFL fail:");
                            exit(1);
                    }   
                    flags |= O_NONBLOCK;
                    if(fcntl(STDOUT_FILENO,F_SETFL,flags)==-1)
                    {   
                            perror("fcntl F_SETFL fail:");
                            exit(1);
                    }   
                
                    ptr = buf;
                    while(ntowrite > 0)
                    {   
                            nwrite = write(STDOUT_FILENO,ptr,ntowrite);
                            if(nwrite == -1) 
                            {  

                                    perror("write file fail:");
                            }   
                            if(nwrite > 0)
                            {   
                                    ptr += nwrite;
                                    ntowrite -= nwrite;
                            }   
                    }   
                
                    flags &= ~O_NONBLOCK;
                    if(fcntl(STDOUT_FILENO,F_SETFL,flags)==-1)
                    {   
                            perror("fcntl F_SETFL fail2:");
                    }   
                    return 0;
            }

             

            4. cmd值的F_GETOWN和F_SETOWN:   
            F_GETOWN   取得當前正在接收SIGIO或者SIGURG信號的進程id或進程組id,進程組id返回的是負值(arg被忽略)     
            F_SETOWN   設置將接收SIGIO和SIGURG信號的進程id或進程組id,進程組id通過提供負值的arg來說明(arg絕對值的一個進程組ID),否則arg將被認為是進程id

             5. cmd值的F_GETLK, F_SETLK或F_SETLKW: 獲得/設置記錄鎖的功能,成功則返回0,若有錯誤則返回-1,錯誤原因存于errno。
            F_GETLK    通過第三個參數arg(一個指向flock的結構體)取得第一個阻塞lock description指向的鎖。取得的信息將覆蓋傳到fcntl()的flock結構的信息。如果沒有發現能夠阻止本次鎖(flock)生成的鎖,這個結構將不被改變,除非鎖的類型被設置成F_UNLCK    
            F_SETLK    按照指向結構體flock的指針的第三個參數arg所描述的鎖的信息設置或者清除一個文件的segment鎖。F_SETLK被用來實現共享(或讀)鎖(F_RDLCK)或獨占(寫)鎖(F_WRLCK),同樣可以去掉這兩種鎖(F_UNLCK)。如果共享鎖或獨占鎖不能被設置,fcntl()將立即返回EAGAIN     
            F_SETLKW   除了共享鎖或獨占鎖被其他的鎖阻塞這種情況外,這個命令和F_SETLK是一樣的。如果共享鎖或獨占鎖被其他的鎖阻塞,進程將等待直到這個請求能夠完成。當fcntl()正在等待文件的某個區域的時候捕捉到一個信號,如果這個信號沒有被指定SA_RESTART, fcntl將被中斷

            當一個共享鎖被set到一個文件的某段的時候,其他的進程可以set共享鎖到這個段或這個段的一部分。共享鎖阻止任何其他進程set獨占鎖到這段保護區域的任何部分。如果文件描述符沒有以讀的訪問方式打開的話,共享鎖的設置請求會失敗。

            獨占鎖阻止任何其他的進程在這段保護區域任何位置設置共享鎖或獨占鎖。如果文件描述符不是以寫的訪問方式打開的話,獨占鎖的請求會失敗。

            結構體flock的指針:
            struct flcok 

            short int l_type; /* 鎖定的狀態*/

            //以下的三個參數用于分段對文件加鎖,若對整個文件加鎖,則:l_whence=SEEK_SET, l_start=0, l_len=0
            short int l_whence; /*決定l_start位置*/ 
            off_t l_start; /*鎖定區域的開頭位置*/ 
            off_t l_len; /*鎖定區域的大小*/

            pid_t l_pid; /*鎖定動作的進程*/ 
            };

            l_type 有三種狀態: 
            F_RDLCK   建立一個供讀取用的鎖定 
            F_WRLCK   建立一個供寫入用的鎖定 
            F_UNLCK   刪除之前建立的鎖定

            l_whence 也有三種方式: 
            SEEK_SET   以文件開頭為鎖定的起始位置 
            SEEK_CUR   以目前文件讀寫位置為鎖定的起始位置 
            SEEK_END   以文件結尾為鎖定的起始位置


            fcntl文件鎖有兩種類型:建議性鎖和強制性鎖
            建議性鎖是這樣規定的:每個使用上鎖文件的進程都要檢查是否有鎖存在,當然還得尊重已有的鎖。內核和系統總體上都堅持不使用建議性鎖,它們依靠程序員遵守這個規定。
            強制性鎖是由內核執行的:當文件被上鎖來進行寫入操作時,在鎖定該文件的進程釋放該鎖之前,內核會阻止任何對該文件的讀或寫訪問,每次讀或寫訪問都得檢查鎖是否存在。

            系統默認fcntl都是建議性鎖,強制性鎖是非POSIX標準的。如果要使用強制性鎖,要使整個系統可以使用強制性鎖,那么得需要重新掛載文件系統,mount使用參數 -0 mand 打開強制性鎖,或者關閉已加鎖文件的組執行權限并且打開該文件的set-GID權限位。
            建議性鎖只在cooperating processes之間才有用。對cooperating process的理解是最重要的,它指的是會影響其它進程的進程或被別的進程所影響的進程,舉兩個例子:
            (1) 我們可以同時在兩個窗口中運行同一個命令,對同一個文件進行操作,那么這兩個進程就是cooperating  processes
            (2) cat file | sort,那么cat和sort產生的進程就是使用了pipe的cooperating processes

            使用fcntl文件鎖進行I/O操作必須小心:進程在開始任何I/O操作前如何去處理鎖,在對文件解鎖前如何完成所有的操作,是必須考慮的。如果在設置鎖之前打開文件,或者讀取該鎖之后關閉文件,另一個進程就可能在上鎖/解鎖操作和打開/關閉操作之間的幾分之一秒內訪問該文件。當一個進程對文件加鎖后,無論它是否釋放所加的鎖,只要文件關閉,內核都會自動釋放加在文件上的建議性鎖(這也是建議性鎖和強制性鎖的最大區別),所以不要想設置建議性鎖來達到永久不讓別的進程訪問文件的目的(強制性鎖才可以);強制性鎖則對所有進程起作用。

            fcntl使用三個參數 F_SETLK/F_SETLKW, F_UNLCK和F_GETLK 來分別要求、釋放、測試record locks。record locks是對文件一部分而不是整個文件的鎖,這種細致的控制使得進程更好地協作以共享文件資源。fcntl能夠用于讀取鎖和寫入鎖,read lock也叫shared lock(共享鎖), 因為多個cooperating process能夠在文件的同一部分建立讀取鎖;write lock被稱為exclusive lock(排斥鎖),因為任何時刻只能有一個cooperating process在文件的某部分上建立寫入鎖。如果cooperating processes對文件進行操作,那么它們可以同時對文件加read lock,在一個cooperating process加write lock之前,必須釋放別的cooperating process加在該文件的read lock和wrtie lock,也就是說,對于文件只能有一個write lock存在,read lock和wrtie lock不能共存。

            posted @ 2013-01-15 10:57 鑫龍 閱讀(4037) | 評論 (0)編輯 收藏

                 摘要: 回顧:  多進程的問題:數據共享。  多進程的問題: 進程的上下文環境(context)          文件描述符號是整數以及對應上下文環境  多進程的問題:上下文環境共享一.SELECT TCP服務器編程模式 1....  閱讀全文

            posted @ 2013-01-13 11:04 鑫龍 閱讀(406) | 評論 (0)編輯 收藏

                     轉載請注明 出自:http://m.shnenglu.com/mysileng/archive/2013/01/11/197202.html

                 討論兩個由sigchld信號引起的血案問題,討論的環境是服務端的并發程序。我們先把最原始的服務器端并發程序模型貼出來:

                 以上是服務器端程序,我們先不看被注視掉的部分,程序對于每一個accept的TCP連接會產生一個子進程,交給子進程去處理。而子進程其實并不做什么,直接睡眠3秒就結束。可以想象這樣當子進程exit以后,會給父進程發sigchld信號,通知父進程自己掛了。但是在我們的父進程中,我們對于sigchld信號采用默認處置(忽略)。結果可想而知就是來一個連接,就產生一個僵死進程。我們運行程序3次,看看是否會得到3個僵死進程。
            服務器端運行程序,被某客戶端連接3次:

            客戶端運行程序執行3次,并查看進程情況:

                首先聲明,我們用客戶端可以查看服務器端進程的原因是,我們把客戶端和服務端放在了一臺電腦上進程本次試驗。我們并不關心cli客戶端的具體實現,因為服務器并不從客戶端獲取任何信息。
                從結果可知,果然服務端果斷產生了3個僵死進程。接下來我們加上對sigchld的處理程序。但加上以后也將產生我們的第一個血案:

            白色為客戶端,黑為服務端:

                可見,僵死進程的問題已經解決,但還有個潛在的隱藏危機。
                PHOSIX對于向accept這種慢速的系統系統調用有一個基本規則(apue,unp都有涉及):當進程阻塞于某個慢系統調用的時候(我們的程序是accept),當進程捕捉到某個信號(我們的程序是sigchld),并從信號的處理函數返回時(我的程序是deal函數),進程不再阻塞與之前的慢速系統調用,而是返回一個EINTER錯誤。
                 對于上面的這個規則,各個操作系統的對待方式是不同的。有的操作系統返回EINTER以后,就會自動重啟之前的慢速系統調用而繼續,有些則不會自動重啟。對我們實驗程序的這個操作系統環境(centos5.5),從結果來看,因為并沒打印"accept error"并退出程序,我猜想,centos5.5應該是會自動重啟慢速系統調用的。也就是說在這里我因為操作系統的優秀,躲過一劫(躲過第一次血案)。但為了可移植性我們應該改進程序為以下實現:

                我的改動主要集中在對accpt的錯誤處理里面。接下來闡述另外一個血案
            ----------------------------------------------------------------------------
                我們繼續沿用上述的最后一次服務端程序來進行接下來的實驗,現在我們編寫一個客戶端程序,客戶端一次性跟服務端申請5個連接。客戶端的程序如下:

               整個程序的構架大概如下:

                這里客戶端最需要注意的是程序的最后一句并不是一個個close所有的套接字描述符,而是調用exit程序結束進程。根據APUE描述,exit系統調用會執行關閉該進程所有描述符的操作,也就是說客戶端的所有描述符,包括套接字描述符也被幾乎同時關閉了。也就是說服務端的由監聽進程產生的所有處理子進程也會在幾乎同時死掉。那么就會在幾乎同時給父進程發送sigchld信號。情況如下:

                血案即將發生。請注意,根據APUE對于信號在1-31之內的的信號,因為歷史原因,是不可靠信號,也就說,SIGCHLD信號在被遞送到正在阻塞SIGCHLD信號的進程時,是不會排隊的,而是會被系統壓縮。上述問題就是當5個sigchld信號幾乎同時到達父進程時,只有第一個能順利被父進程的信號處理函數處理。又因為被signal/sigaction設置的信號處理函數會自動阻塞正在處理的信號這一原則,接下來沒被處理的4個sigchld信號,被排在了父進程門口。不巧的是,sigchld又是不可靠信號,結果是4個sigchld被壓縮成一個sigchld信號。這就導致信號的丟失。也因為丟失了3個sigchld信號,就會產生3個僵尸進程。你說這是不是一個名符其實的血案。接下來我們實驗一下:

                可以清晰的看到結果如預期,所有出現信號丟失導致3個僵死進程。那么怎么解決這個問題呢?~。。。。

            posted @ 2013-01-11 18:54 鑫龍 閱讀(1489) | 評論 (1)編輯 收藏

                 摘要: 一.TCP的編程模型 回顧:  UDP模型的UML圖  TCP模型的UML圖 案例1:  TCP的服務器(在案例中使用瀏覽器作為客戶程序)   socket建立服務器的文件描述符號緩沖 bind把IP地址與端口設置到文件描述符號中 listen負責根據客戶連接的不同IP...  閱讀全文

            posted @ 2013-01-10 12:49 鑫龍 閱讀(431) | 評論 (0)編輯 收藏

            網絡IP地址本是用32位二進制來表示的,為了記憶的方便可以用點分十進制來表示IP地址,同時,網絡IP地址在網絡傳輸和計算機內部的存儲方式也不同,需要用函數來進行轉換。 

            1.將點分十進制字符串轉換成十進制長整型數:in_addr_t inet_addr(const char *cp);       in_addr_t 即long型,參數cp表示一個點分十進制字符串,返回值是十進制長整型數。 

            2.將長整型IP地址轉換成點分十進制:char *inet_ntoa(struct in_addr in);   參數in是一個in_addr類型的結構體,這個結構體在man 7 ip中查得到:
              struct in_addr{
                 uint32_t s_addr
              };
            inet_ntoa返回的是點分十進制的IP地址字符串。
             

            3.主機字符順序和網絡字符順序的轉換:計算機中的字符和網絡中的字符的存儲順序是不同的,計算機中的整型數和網絡中的整型數進行交換時,需要相關的函數進行轉換。如果將計算機中的長整型IP地址轉換成網絡字符順序的整型IP地址,使用htonl函數。這些函數如下:

            uint32_t htonl(uint32_t hostlong);將計算機中的32位長整型數轉換成網絡字符順序的32位長整型數。(用于IP的轉換)

            uint16_t htons(uint16_t hostshort);將計算機中的16位整型數轉換成網絡字符順序的16位整型數。。(用于port的轉換)

            uint32_t ntohl(uint32_t netlong);將網絡中的32位常整型數轉換成計算機中的32位長整型數。。(用于IP的轉換)

            uint16_t ntons(uint16_t netshort);將網絡中的16位整型數轉換成計算機中的16位整型數。。(用于port的轉換)

            轉自:
            http://www.linuxidc.com/Linux/2012-01/51068.htm

            posted @ 2013-01-09 18:02 鑫龍 閱讀(604) | 評論 (0)編輯 收藏

            僅列出標題
            共20頁: First 4 5 6 7 8 9 10 11 12 Last 
            国产精品久久久久久| 久久精品无码一区二区WWW| 狠狠色丁香婷综合久久| 2021国产成人精品久久| 久久精品中文字幕有码| 久久久久久久久波多野高潮| 久久精品人人做人人爽电影蜜月| 国产精品综合久久第一页| 久久亚洲精品成人无码网站| 国产99久久精品一区二区| 久久夜色精品国产www| 狠狠综合久久AV一区二区三区| 久久91精品国产91久久麻豆 | 日韩精品无码久久一区二区三| 污污内射久久一区二区欧美日韩 | 国内精品久久久久久久97牛牛| AA级片免费看视频久久| 久久免费的精品国产V∧| 精品无码人妻久久久久久 | 亚洲а∨天堂久久精品| 久久久久四虎国产精品| 久久久精品人妻一区二区三区蜜桃| 大伊人青草狠狠久久| 精品久久久久成人码免费动漫 | 精品久久久中文字幕人妻| 热RE99久久精品国产66热| 色综合久久88色综合天天| 97久久天天综合色天天综合色hd| 少妇无套内谢久久久久| 色狠狠久久综合网| 欧美日韩中文字幕久久久不卡| 国产激情久久久久影院| 久久96国产精品久久久| 久久精品国产只有精品2020| 久久精品国产亚洲av日韩| 久久久免费精品re6| 日韩精品久久久肉伦网站| 亚洲AV成人无码久久精品老人| 久久无码专区国产精品发布| 亚洲午夜精品久久久久久浪潮| 少妇久久久久久被弄到高潮 |