• <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>

            Just enjoy programming

            #

            linux RPC 測試(轉載)

            轉自:
            http://www.justwinit.cn/post/3960/


            RPC是glibc提供的函數參數/返回值封裝服務, 并將封裝結果通過網絡傳到服務器.
            RPC服務端首先要啟動portmapper服務.
            測試一個簡單的RPC傳輸示例, 先定義一個模板文件test.x

            program TESTPROG{
                    version VERSION{
                            int int_echo(int)=1;
                            int get_str_len(string)=2;
                            int add ( int, int ) = 3;
                    }=1;
            }=30000;
            內含3個函數, 注意其中一個有2個參數.
            然后可以用rpcgen生成一個Makefile:

            rpcgen -a -N test.x

            這會生成Makefile, 客戶端和服務端的程序, 和函數示例.
            我們手工修改一下Makefile

            # This is a template Makefile generated by rpcgen
            # Parameters
            CLIENT = test_client
            SERVER = test_server
            SOURCES_CLNT.c =
            SOURCES_CLNT.h =
            SOURCES_SVC.c =
            SOURCES_SVC.h =
            SOURCES.x = test.x
            TARGETS_SVC.c = test_svc.c test_server.c test_xdr.c
            TARGETS_CLNT.c = test_clnt.c test_client.c test_xdr.c
            TARGETS = test.h test_xdr.c test_clnt.c test_svc.c
            OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o)
            OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o)
            # Compiler flags
            CFLAGS += -g -pipe
            LDLIBS += -lnsl
            RPCGENFLAGS = -N
            # Targets
            all : $(CLIENT) $(SERVER)
            $(TARGETS) : $(SOURCES.x)
                    rpcgen $(RPCGENFLAGS) $(SOURCES.x)
            $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c)
            $(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c)
            $(CLIENT) : $(OBJECTS_CLNT)
                    $(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS)
            $(SERVER) : $(OBJECTS_SVC)
                    $(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)
            clean:
                     $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER)

            修改test_server.c服務端的處理函數, 提供3種服務:

            /*
            * This is sample code generated by rpcgen.
            * These are only templates and you can use them
            * as a guideline for developing your own functions.
            */
            #include "test.h"
            int *
            int_echo_1_svc(int arg1,  struct svc_req *rqstp)
            {
                    static int  result;
                    //echo.
                    result=arg1;
                    printf("[RPC1] source=%d, echo=%d\n", arg1, result);
                    return &result;
            }
            int *
            get_str_len_1_svc(char *arg1,  struct svc_req *rqstp)
            {
                    static int  result;
                    //get strlen.
                    result=strlen(arg1);
                    printf("[PRC2] str=%s, len=%d\n", arg1, result);
                    return &result;
            }
            int *
            add_1_svc(int arg1, int arg2,  struct svc_req *rqstp)
            {
                    static int  result;
                    result=arg1+arg2;
                    printf("[RPC3] %d+%d=%d\n", arg1, arg2, result);
                    return &result;
            }

            客戶端test_client.c, 調用這三種服務:

            /*
            * This is sample code generated by rpcgen.
            * These are only templates and you can use them
            * as a guideline for developing your own functions.
            */
            #include "test.h"
            void
            testprog_1(char *host)
            {
                    CLIENT *clnt;
                    int  *result_1;
                    int int_echo_1_arg1=55;
                    int  *result_2;
                    char *get_str_len_1_arg1="Hello, world";
                    int  *result_3;
                    int add_1_arg1=10;
                    int add_1_arg2=20;
                    clnt = clnt_create (host, TESTPROG, VERSION, "udp");
                    if (clnt == NULL) {
                            clnt_pcreateerror (host);
                            exit (1);
                    }
                    result_1 = int_echo_1(int_echo_1_arg1, clnt);
                    if (result_1 == (int *) NULL) {
                            clnt_perror (clnt, "call failed");
                    }
                    else
                            printf("[PRC1] echo %d, source %d\n", *result_1,
                                    int_echo_1_arg1);
                    result_2 = get_str_len_1(get_str_len_1_arg1, clnt);
                    if (result_2 == (int *) NULL) {
                            clnt_perror (clnt, "call failed");
                    }
                    else
                            printf("[RPC2] return %d, should %d\n", *result_2,
                                    strlen(get_str_len_1_arg1));
                    result_3 = add_1(add_1_arg1, add_1_arg2, clnt);
                    if (result_3 == (int *) NULL) {
                            clnt_perror (clnt, "call failed");
                    }
                    else
                            printf("[PRC3] %d+%d=%d\n", add_1_arg1, add_1_arg2,
                                    *result_3);
                    clnt_destroy (clnt);
            }
            OK, 可以調用make了.
            生成可執行程序test_server和test_client.
            我們啟動./test_server, 用rpcinfo看看:

            $rpcinfo -p 127.0.0.1
            program vers proto port
            100000 2 tcp 111 portmapper
            30000 1 udp 36307
            30000 1 tcp 34883
            Bingo! 啟動成功.

            再開個終端, 嘗試一下調用.

            ./test_client 127.0.0.1
            [PRC1] echo 55, source 55
            [RPC2] return 12, should 12
            [PRC3] 10+20=30

            正是我們期望的.

            Add By:Jackxiang
            make -f Makefile.test

            posted @ 2011-08-07 16:44 周強 閱讀(1188) | 評論 (0)編輯 收藏

            最近的我

               最近的我狀態不錯,睡眠也好了很多,每天7點半左右起床,每天看看資料,看看論文,編編程序,晚上10點半左右回到宿舍,洗個澡上上網就睡覺了,周末去圖書館看看書或者實驗室待著。這樣的生活挺好的,就是現在每天坐車有點累。現在的心態確實不錯,不再多想了,不再去想以后會去哪,以后該做什么,一切都隨緣吧,每天都盡量努力點,把能做的事給做好。
               最近的動車相撞確實挺讓人糾心的。單就技術方面我感覺我們的高鐵和動車還是有很大問題的,有點大躍進,買國外的技術然后自己改裝下,就說是處于世界領先水平了。技術的創新是需要長時間的積累的,我感覺我們目前最多只是個模仿者,更別談創新了。我感覺很多方面我們是缺少創新的,單就計算機方面,國內最近炒得很熱的云計算,好像很多公司都在搞,看上去很創新,但我感覺是缺乏技術積累的,很多公司目前只是在用國外的開源軟件做做研究,到目前為止都沒有一個像亞馬遜,谷歌一樣的數據中心。

            posted @ 2011-07-31 20:18 周強 閱讀(275) | 評論 (3)編輯 收藏

            Nginx源碼分析-Epoll模塊(轉載)

            轉載自:http://www.tbdata.org/archives/1296


            Nginx源碼分析-Epoll模塊

            3 comments 十二月 26th, 2010 | by yixiao in 高性能服務器

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

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

            ngx_event_module_t  ngx_epoll_module_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的相關初始化工作,代碼分析如下:

            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_module);
            	/*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 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_module_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_module_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,這個函數主要用來完成事件的等待并處理。

            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 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還有添加事件和刪除事件等的相關函數,代碼都很簡單,本文就不做具體的分析了。

            posted @ 2011-07-10 00:54 周強 閱讀(943) | 評論 (0)編輯 收藏

            linux 進程間通信之消息傳遞

            linux 進程間通信中消息傳遞主要分為管道,FIFO,消息隊列
            (1)管道
            管道由pipe函數創建,提供一個單路(單向)數據流。pipe函數返回兩個文件描述符:fd[0]和fd[1]。前者打開來讀,后者打開來寫。管道沒有名字,所以只能由有親緣關系的進程使用。盡管管道是由單個進程創建的,它卻很少在單個進程內使用。管道的典型用途為兩個不同進程(一個是父進程,一個是子進程)提供進程間的通信手段。首先,由一個進程(它將成為父進程)創建一個管道后調用fork派生一個自身的副本。接著,父進程關閉這個管道的讀出端,子進程關閉同一管道的寫入端。或者父進程關閉這個管道的寫入端,子進程關閉同一管道的讀出端。這就在父子進程間提供了一個單向數據流。

            (2)FIFO
            FIFO指代先進先出(First in,First out),linux中的FIFO類似管道。它是一個單向(半雙工)數據流。不同于管道的是,每個FIFO有一個路徑名與之關聯,從而允許無親緣關系的進程訪問同一個FIFO。FIFO也稱為有名管道。FIFO由mkfifo函數創建。其中pathname是一個普通的Unix路徑名,它是該FIFO的名字。mkfifo 函數已隱含指定 O_CREAT|O_EXCL. 也就是說,它那么創建一個新的FIFO,要么返回一個EEXIST錯誤(如果所指定的名字的FIFO已經存在)。如果不想希望創建一個新的FIFO,那就改為調用open而不是mkfifo.要打開一個已存在的FIFO或創建一個新的FIFO,應先調用mkfifo,再檢查它是否返回EEXIST錯誤,若返回該錯誤則改為調用open.mkfifo 命令也能創建FIFO。可以從shell腳本或命令行中使用它。在創建出一個FIFO后,它必須或者打開來讀,或者打開來寫,所用的可以是open函數,也可以是某個標準I/O打開函數。FIFO不能打開來既讀又寫,因為它是半雙工的。對管道或FIFO的write總是往末尾添加數據,對它們的read則總是從開頭返回數據。如果對管道或FIFO調用lseek,那就返回ESPIPE錯誤。

            (3)Posix 消息隊列
            消息隊列可認為是一個消息鏈表。有足夠寫權限的線程可往隊列中放置消息,有足夠讀權限的線程可從隊列中取走消息。每個消息都是一個記錄,它由發送者賦予一個優先級。在某個進程往一個隊列寫入消息之前,并不需要另外某個進程在該隊列上等待消息的到達。這跟管道和FIFO是相反的,對后者來說,除非讀出者已存在,否則先有寫入者是沒有意義的。一個進程可以往某個隊列寫入一些消息,然后終止,再讓另外一個進程在以后某個時刻讀出這些消息。消息隊列具有隨內核的持續性,這跟管道和FIFO不一樣。Posix消息隊列和System V消息隊列。這兩組函數間存在許多相似性,但也有主要的區別
            1. 對Posix消息隊列的讀總是返回最高優先級的最早消息,對System V消息隊列的讀則可以返回任意指定優先級的消息。
            2.當往一個空隊列放置一個消息時,Posix 消息隊列允許產生一個信號或啟動一個線程。System V消息隊列則不提供類似機制。

            隊列中的每個消息具有如下屬性:
            1.一個無符號整數優先級(Posix)或一個長整數類型(System V).
            2.消息的數據部分長度(可以為0).
            3.數據本身(如果長度大于0)

            函數接口
            1. mqd_t mq_open(const char *name,int oflag,...)
            mq_open函數創建一個新的消息隊列或打開一個已存在的消息隊列
            2.int mq_close(mqd_t mqdes);
            mq_close函數關閉一個消息隊列。
            3.int mq_unlink(const char *name);
            從系統中刪除用作第一個參數的某個name.
            4. int mq_getattr(mqd_t mqdes,struct mq_attr *attr);
               int mq_setattr(mqd_t mqdes,const struct mq_attr *attr,struct mq_attr *oattr);
            每個消息隊列有四個屬性,mq_getattr返回所有這些屬性,mq_setattr則設置其中某個屬性。
            struct mq_attr{
               long mq_flags;
               long mq_maxmsg;
               long mq_msgsize;
               long mq_curmsgs;
            };
            5.int mq_send(mqd_t mqdes,const char *ptr,size_t len,unsigned int prio);
             int mq_receive(mqd_t mqdes,char *ptr,size_t len,unsigned int *priop);
            mq_send函數往消息隊列中寫入消息,mq_receive函數從消息隊列中讀出消息。

            6.int mq_notify(mqd_t mqdes,const struct sigevent *motification);
            結構體:
            union sigval{
                int sival_int;
                void *sival_ptr;
            };

            struct sigevent
            {
                int sigev_notify;
                int sigev_signo;
                union sigval sigev_value;
                void  (*sigev_notify_function)(union sigval);
                pthread_attr_t *sigev_notify_attributes;
            };
            mq_notify函數為指定隊列建立或刪除異步事件通知。一些普遍適用于該函數的若干規則
            1).如果notification參數非空,那么當前進程希望在一個消息達到所指定的先前為空的隊列時得到通知。我們說"該進程被注冊為接收該隊列的通知"。
            2).如果notification參數為空指針,而且當前進程目前被注冊為接收所指定隊列的通知,那么已存在的注冊將被撤銷。
            3).任意時刻只有一個進程可以被注冊為接收某個給定隊列的通知。
            4).當有一個消息達到某個先前為空的隊列,而且已有一個進程被注冊為接收該隊列的通知時,只有在沒有任何線程阻塞在該隊列的mq_receive調用中的前提下,通知才會發出。這就是說,在mq_receive調用中的阻塞比任何通知的注冊都優先。
            5).當該通知被發送給它的注冊進程時,其注冊即被撤銷。該進程必須再次調用mq_notify以重新注冊(想要的話)。

            參考:Unix進程間通信

            posted @ 2011-07-07 02:29 周強 閱讀(3036) | 評論 (3)編輯 收藏

            近期計劃

                 最近的思緒有點亂,離找工作只剩7,8,9三個月了,該是好好計劃下。
             (1)盡快把論文寫完
             (2)找工作前要要看完的書
            unix三卷書(就剩unix進程間通信),TCP/IP 詳解(卷一),c++編程思想2卷書,effective c++,STL源碼分析,設計模式,算法導論,編程之美,程序員面試寶典
            (3)源碼閱讀  nginx 閱讀

            posted @ 2011-07-06 12:37 周強 閱讀(335) | 評論 (4)編輯 收藏

                 晚上獨自一個人走在校園里,感覺特別的安靜,我喜歡這種平靜的生活,可能是因為這么多年一個人習慣了,有時候更喜歡一個人靜靜地待著,不用去理會其他人,可以獨自地思考。我感覺我以前缺少一個勇敢的心,不敢去追求一些美好的事物,錯過了很多東西。很多事是沒有對錯的,只在于自己的選擇。既然是自己做的選擇就不應該去后悔什么,或許當初不這樣選擇我會變得更好,但至少現在的我應該感謝當初的選擇,因為當初的選擇才有現在的自己。突然想到了大姐說的一個詞“自律”,我感覺我有時真得太過自律了,有時候真想去放縱自己,羨慕那些把人生當游戲的人,人生得意須盡歡,但我卻做不到,因為我知道我身上有很多責任,有很多事情需要去做。
                上周打家里電話,我爸問我是不是要放暑假了,我能聽出來他們想讓我回家看看了,我也很想回家看看,但最近我真得很忙,估計是沒時間回去了,只能等到過年的時候再回去了。
                上周末去醫院,發現有些數字確實有點高了,可能是因為長時間的壓力與睡眠不好造成的,是時候該為自己減減壓了,現在想想我真有點杞人憂天,很多事情我都可以不去想的。現在開始要堅持跑步鍛煉身體,好好改善睡眠了。要學會平靜地面對一切,簡單點,淡定點,不是非要做的事就不去想了,船到橋頭自然直。
               

            posted @ 2011-07-04 21:38 周強 閱讀(277) | 評論 (2)編輯 收藏

            linux 進程間通信綜述

            linux進程間通信主要分為以下4個領域
            (1)消息傳遞(管道,FIFO,消息隊列)
            (2)同步(互斥鎖,條件變量,讀寫鎖,信號量)
            (3)共享內存區(匿名共享內存區,有名共享內存區)
            (4)過程調用(Solaris門,Sun RPC)


            linux進程間的信息共享可以分為
            (1) 基于文件系統的共享
            (2) 基于內核的共享
            (3) 基于共享內存區的共享


            IPC對象的持續性
            (1)隨進程間持續的IPC對象一直存在到打開著該對象的最后一個進程關閉該對象的最后一個進程關閉該對象為止。
            (2)隨內核持續的IPC對象一直存在到內核重新自舉或顯式刪除該對象為止。
            (3)隨文件系統持續的IPC對象一直存在到顯示刪除該對象為止。即使系統自舉了,該對象還是存在的。


            IPC類型                                       持續性
            管道                                           隨進程
            FIFO                                          隨進程

            Posix互斥鎖                                 隨進程
            Posix條件變量                              隨進程
            Posix讀寫鎖                                 隨進程
            fcntl記錄上鎖                                隨進程

            Posix消息隊列                              隨內核
            Posix有名信號量                           隨內核
            Posix基于內存的信號量                   隨進程
            Posix共享內存區                           隨內核

            System V消息隊列                        隨內核
            System V信號量                           隨內核
            System V共享內存區                     隨內核

            TCP套接字                                  隨進程
            UDP套接字                                  隨進程
            Unix域套接字                               隨進程






            名字空間:
            當兩個或多個無親緣關系的進程使用某種類型的IPC對象來彼此交換信息時,該IPC對象必須有一個某種形式的名字或者標識符,這樣其中一個進程(往往是服務器)可以創建該IPC對象,其余進程則可以指定同一個IPC對象。

            IPC類型                        用于打開或創建IPC的名字空間                IPC打開后的標識
            管道                                     沒有名字                                      描述符
            FIFO                                    路徑名                                         描述符

            Posix互斥鎖                          沒有名字                                      pthread_mutex_t指針
            Posix條件變量                       沒有名字                                      pthread_cond_t指針
            Posix讀寫鎖                          沒有名字                                      pthread_rwlock_t指針
            fcntl記錄上鎖                        路徑名                                         描述符

            Posix消息隊列                       Posix IPC名字                              mqd_t值
            Posix有名信號量                    Posix IPC名字                              sem_t指針
            Posix基于內存的信號量            沒有名字                                     sem_t指針
            Posix共享內存區                    Posix IPC名字                              描述符


            System V消息隊列                key_t鍵                                       System V IPC標識符
            System V 信號量                  key_t鍵                                       System V IPC標識符
            System V共享內存區              key_t鍵                                      System V IPC 標識符

            門                                      路徑名                                         描述符
            sun RPC                             程序/版本                                     RPC句柄

            TCP套接字                            IP地址與TCP 端口                         描述符
            UDP套接字                           IP地址與UDP端口                          描述符
            Unix域套接字                        路徑名                                        描述符  

            posted @ 2011-07-04 09:58 周強 閱讀(10884) | 評論 (3)編輯 收藏

               最近一直在下雨,有好幾次都被淋濕了,不過想想偶爾淋淋雨感覺也挺好的。我還是挺喜歡下雨的,可能跟我的性格有點關系,眼神中總有一絲的憂愁。記得小時候下雨的時候總喜歡坐在家門口的傻傻地看著雨。雨總能給我帶來一種安靜的感覺,下雨天在實驗室看看書對于我來說可以算是一種享受,可以不去想一些煩心事,可以讓我浮躁的心靜下來。高中有空閑下來的時候喜歡讀會詩,雨巷是其中一首比較喜歡的詩。

            雨巷

            作者: 戴望舒

             
            撐著油紙傘,獨自
            彷徨在悠長、悠長
            又寂寥的雨巷
            我希望逢著
            一個丁香一樣地
            結著愁怨的姑娘
             
            她是有
            丁香一樣的顏色
            丁香一樣的芬芳
            丁香一樣的憂愁
            在雨中哀怨
            哀怨又彷徨
             
            她彷徨在這寂寥的雨巷
            撐著油紙傘
            像我一樣
            像我一樣地
            默默彳亍著
            寒漠、凄清,又惆悵
             
            她默默地走近
            走近,又投出
            太息一般的眼光
            她飄過
            像夢一般地
            像夢一般地凄婉迷茫
             
            像夢中飄過
            一枝丁香地
            我身旁飄過這女郎
            她靜默地遠了、遠了
            到了頹圮的籬墻
            走盡這雨巷
             
            在雨的哀曲里
            消了她的顏色
            散了她的芬芳
            消散了,甚至她的
            太息般的眼光
            丁香般的惆悵
             
            撐著油紙傘,獨自
            彷徨在悠長、悠長
            又寂寥的雨巷
            我希望飄過
            一個丁香一樣地
            結著愁怨的姑娘


            posted @ 2011-06-30 17:12 周強 閱讀(315) | 評論 (5)編輯 收藏

            linux 守護進程編寫規則

            linux 守護進程編寫規則

            (1)首先要做的是調用umask將文件模式創建屏蔽字設置為0.由繼承得來的文件模式創建屏蔽字可能會拒絕設置某些權限。
            (2)調用fork,然后使父進程退出(exit).這樣做實現了下面幾點:第一,如果該守護進程是作為一條簡單shell命令啟動的,那么父進程終止使得shell認為這條命令已經執行完畢。第二,子進程繼承了父進程的進程組ID,但具有一個新的進程ID,這就保證了子進程不是一個進程組的組長進程。這對于下面就要做的setsid調用是必要的前提條件。
            (3)調用setsid以創建一個新會話,是調用進程:(a)成為新會話的首進程,(b)成為一個新進程組的組長進程,(c)沒有控制終端。在有些人建議在此時再次調用 fork,并是父進程終止。第二個子進程作為守護進程繼續運行。這樣就保證了該守護進程不是會話首進程。
            (4)將當前工作目錄更改為根目錄。
            (5)關閉不再需要的文件描述符。這使守護進程不再持有從其父進程繼承來的某些文件描述符。
            (6)某些守護進程打開/dev/null使其具有文件描述符0,1,2.這樣,任何一個試圖讀標準輸入,寫標準輸出或標準出錯的庫例程都不會產生任何效果。

            參考:UNIX環境高級編程

            posted @ 2011-06-29 21:50 周強 閱讀(2173) | 評論 (1)編輯 收藏

            nginx源碼分析 ngx_palloc.h ngx_palloc.c

            ngx_palloc.h 和 ngx_palloc.c主要用于nginx管理內存池

            #include <ngx_config.h>
            #include <ngx_core.h>


            /*
             * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
             * On Windows NT it decreases a number of locked pages in a kernel.
             */
            #define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)
            //內存池默認大小
            #define NGX_DEFAULT_POOL_SIZE    (16 * 1024)

            //#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1)) 將d向上取a的倍數。

            #define NGX_POOL_ALIGNMENT       16
            //內存池的最小大小,為16的倍數
            #define NGX_MIN_POOL_SIZE                                                     \
                ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \
                          NGX_POOL_ALIGNMENT)

            //ngx_pool_cleanup_pt 為函數指針
            typedef void (*ngx_pool_cleanup_pt)(void *data);

            typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;
            //這個結構用來表示內存池中的數據的清理handler
            //handler表示清理函數,data表示傳遞給清理函數的數據,next表示下一個清理handler,
            //也就是說當destroy這個pool的時候會遍歷清理handler鏈表,然后調用handler.
            struct ngx_pool_cleanup_s {
                ngx_pool_cleanup_pt   handler;
                void                 *data;
                ngx_pool_cleanup_t   *next;
            };


            typedef struct ngx_pool_large_s  ngx_pool_large_t;
            //該結構表示大塊內存,這個結構很簡單,就是一個指針指向下一塊large,一個alloc指向數據
            struct ngx_pool_large_s {
                ngx_pool_large_t     *next;
                void                 *alloc;
            };

            //數據區的指針ngx_pool_data_t。其中last表示當前的數據區的已經使用的數據的結尾。
            //end表示當前的內存池的結尾。也就是說end-last就是內存池未使用的大小。
            typedef struct {
                u_char               *last;
                u_char               *end;
            //指向下一塊內存池
                ngx_pool_t           *next;
            //申請該內存池失敗的標記
                ngx_uint_t            failed;
            } ngx_pool_data_t;


            struct ngx_pool_s {
                ngx_pool_data_t       d;
                size_t                max;
                ngx_pool_t           *current;
                ngx_chain_t          *chain;
                ngx_pool_large_t     *large;
                ngx_pool_cleanup_t   *cleanup;
                ngx_log_t            *log;
            };


            typedef struct {
                ngx_fd_t              fd;
                u_char               *name;
                ngx_log_t            *log;
            } ngx_pool_cleanup_file_t;


            void *ngx_alloc(size_t size, ngx_log_t *log);
            void *ngx_calloc(size_t size, ngx_log_t *log);

            ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
            void ngx_destroy_pool(ngx_pool_t *pool);
            void ngx_reset_pool(ngx_pool_t *pool);

            void *ngx_palloc(ngx_pool_t *pool, size_t size);
            void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
            void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
            void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
            ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);


            ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
            void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
            void ngx_pool_cleanup_file(void *data);
            void ngx_pool_delete_file(void *data);


            #endif /* _NGX_PALLOC_H_INCLUDED_ */

            posted @ 2011-06-16 18:12 周強 閱讀(469) | 評論 (0)編輯 收藏

            僅列出標題
            共6頁: 1 2 3 4 5 6 
            国产V综合V亚洲欧美久久| 伊人色综合久久天天网| 亚洲精品无码成人片久久| 国产香蕉久久精品综合网| 人妻无码αv中文字幕久久| 99久久夜色精品国产网站| 久久久精品国产Sm最大网站| 欧美亚洲国产精品久久高清| 无码人妻久久一区二区三区免费| 国产精品久久久天天影视| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲乱码日产精品a级毛片久久 | 久久精品无码专区免费| 久久亚洲视频| 久久久久18| 91精品国产91久久久久福利| 国产精品成人无码久久久久久| 久久综合香蕉国产蜜臀AV| 久久免费99精品国产自在现线| 久久精品国产亚洲麻豆| 国产亚洲精品自在久久| 国产午夜精品理论片久久 | 色88久久久久高潮综合影院| 国产成人精品久久亚洲高清不卡 | 精品综合久久久久久888蜜芽| 一本久久综合亚洲鲁鲁五月天| a级毛片无码兔费真人久久| 99久久国产宗和精品1上映| 久久精品国产清自在天天线 | 亚洲国产天堂久久综合网站| 久久久精品人妻一区二区三区四 | 亚洲日本va午夜中文字幕久久| 久久99精品久久久久久秒播| 国内精品久久久久影院一蜜桃| 国产香蕉久久精品综合网| 久久久久久久久久久免费精品| 国产精品午夜久久| 93精91精品国产综合久久香蕉| 日韩亚洲欧美久久久www综合网| 国内精品久久久久久麻豆| 99精品久久久久中文字幕|