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

            大龍的博客

            常用鏈接

            統(tǒng)計(jì)

            最新評(píng)論

            send或者write socket遭遇SIGPIPE信號(hào)(轉(zhuǎn))

            當(dāng)服務(wù)器close一個(gè)連接時(shí),若client端接著發(fā)數(shù)據(jù)。根據(jù)TCP協(xié)議的規(guī)定,會(huì)收到一個(gè)RST響應(yīng),client再往這個(gè)服務(wù)器發(fā)送數(shù)據(jù)時(shí),系統(tǒng)會(huì)發(fā)出一個(gè)SIGPIPE信號(hào)給進(jìn)程,告訴進(jìn)程這個(gè)連接已經(jīng)斷開了,不要再寫了。

            又或者當(dāng)一個(gè)進(jìn)程向某個(gè)已經(jīng)收到RST的socket執(zhí)行寫操作是,內(nèi)核向該進(jìn)程發(fā)送一個(gè)SIGPIPE信號(hào)。該信號(hào)的缺省學(xué)位是終止進(jìn)程,因此進(jìn)程必須捕獲它以免不情愿的被終止。


            根據(jù)信號(hào)的默認(rèn)處理規(guī)則SIGPIPE信號(hào)的默認(rèn)執(zhí)行動(dòng)作是terminate(終止、退出),所以client會(huì)退出。若不想客戶端退出可以把 SIGPIPE設(shè)為SIG_IGN

            如:signal(SIGPIPE, SIG_IGN);
            這時(shí)SIGPIPE交給了系統(tǒng)處理。

            服務(wù)器采用了fork的話,要收集垃圾進(jìn)程,防止僵尸進(jìn)程的產(chǎn)生,可以這樣處理:
            signal(SIGCHLD,SIG_IGN);
            交給系統(tǒng)init去回收。
            這里子進(jìn)程就不會(huì)產(chǎn)生僵尸進(jìn)程了。


            在linux下寫socket的程序的時(shí)候,如果嘗試send到一個(gè)disconnected socket上,就會(huì)讓底層拋出一個(gè)SIGPIPE信號(hào)。
            這個(gè)信號(hào)的缺省處理方法是退出進(jìn)程,大多數(shù)時(shí)候這都不是我們期望的。因此我們需要重載這個(gè)信號(hào)的處理方法。調(diào)用以下代碼,即可安全的屏蔽SIGPIPE:
            struct sigaction sa;
            sa.sa_handler = SIG_IGN;
            sigaction( SIGPIPE, &sa, 0 );

            signal設(shè)置的信號(hào)句柄只能起一次作用,信號(hào)被捕獲一次后,信號(hào)句柄就會(huì)被還原成默認(rèn)值了。
            sigaction設(shè)置的信號(hào)句柄,可以一直有效,值到你再次改變它的設(shè)置。

            struct sigaction action;
            action.sa_handler = handle_pipe;
            sigemptyset(&action.sa_mask);
            action.sa_flags = 0;
            sigaction(SIGPIPE, &action, NULL);
            void handle_pipe(int sig)
            {
                    //不做任何處理即可
            }

            RST的含義為“復(fù)位”,它是TCP在某些錯(cuò)誤情況下所發(fā)出的一種TCP分節(jié)。有三個(gè)條件可以產(chǎn)生RST:

            1), SYN到達(dá)某端口但此端口上沒有正在監(jiān)聽的服務(wù)器。
            2), TCP想取消一個(gè)已有連接
            3), TCP接收了一個(gè)根本不存在的連接上的分節(jié)。

            1. Connect 函數(shù)返回錯(cuò)誤ECONNREFUSED:
            如果對(duì)客戶的SYN的響應(yīng)是RST,則表明該服務(wù)器主機(jī)在我們指定的端口上沒有進(jìn)程在等待與之連接(例如服務(wù)器進(jìn)程也許沒有啟動(dòng)),這稱為硬錯(cuò)(hard error),客戶一接收到RST,馬上就返回錯(cuò)誤ECONNREFUSED.

            TCP為監(jiān)聽套接口維護(hù)兩個(gè)隊(duì)列。兩個(gè)隊(duì)列之和不超過listen函數(shù)第二個(gè)參數(shù)backlog。

            當(dāng) 一個(gè)客戶SYN到達(dá)時(shí),若兩個(gè)隊(duì)列都是滿的,TCP就忽略此分節(jié),且不發(fā)送RST.這個(gè)因?yàn)椋哼@種情況是暫時(shí)的,客戶TCP將重發(fā)SYN,期望不久就能在 隊(duì)列中找到空閑條目。要是TCP服務(wù)器發(fā)送了一個(gè)RST,客戶connect函數(shù)將立即發(fā)送一個(gè)錯(cuò)誤,強(qiáng)制應(yīng)用進(jìn)程處理這種情況,而不是讓TCP正常的重 傳機(jī)制來(lái)處理。還有,客戶區(qū)別不了這兩種情況:作為SYN的響應(yīng),意為“此端口上沒有服務(wù)器”的RST和意為“有服務(wù)器在此端口上但其隊(duì)列滿”的 RST.
            Posix.1g允許以下兩種處理方法:忽略新的SYN,或?yàn)榇薙YN響應(yīng)一個(gè)RST.歷史上,所有源自Berkeley的實(shí)現(xiàn)都是忽略新的SYN。

            2.如果殺掉服務(wù)器端處理客戶端的子進(jìn)程,進(jìn)程退出后,關(guān)閉它打開的所有文件描述符,此時(shí),當(dāng)服務(wù)器TCP接收到來(lái)自此客戶端的數(shù)據(jù)時(shí),由于先前打開的那個(gè)套接字接口的進(jìn)程已終止,所以以RST響應(yīng)。

            經(jīng)常遇到的問題:
            如果不判斷read , write函數(shù)的返回值,就不知道服務(wù)器是否響應(yīng)了RST, 此時(shí)客戶端如果向接收了RST的套接口進(jìn)行寫操作時(shí),內(nèi)核給該進(jìn)程發(fā)一個(gè)SIGPIPE信號(hào)。此信號(hào)的缺省行為就是終止進(jìn)程,所以,進(jìn)程必須捕獲它以免不情愿地被終止。

            進(jìn)程不論是捕獲了該信號(hào)并從其信號(hào)處理程序返回,還是不理會(huì)該信號(hào),寫操作都返回EPIPE錯(cuò)誤。


            3. 服務(wù)器主機(jī)崩潰后重啟
            如 果服務(wù)器主機(jī)與客戶端建立連接后崩潰,如果此時(shí),客戶端向服務(wù)器發(fā)送數(shù)據(jù),而服務(wù)器已經(jīng)崩潰不能響應(yīng)客戶端ACK,客戶TCP將持續(xù)重傳數(shù)據(jù)分節(jié),試圖從 服務(wù)器上接收一個(gè)ACK,如果服務(wù)器一直崩潰客戶端會(huì)發(fā)現(xiàn)服務(wù)器已經(jīng)崩潰或目的地不可達(dá),但可能需要比較長(zhǎng)的時(shí)間; 如果服務(wù)器在客戶端發(fā)現(xiàn)崩潰前重啟,服務(wù)器的TCP丟失了崩潰前的所有連接信息,所以服務(wù)器TCP對(duì)接收的客戶數(shù)據(jù)分節(jié)以RST響應(yīng)。

            二、關(guān)于socket的recv:

            對(duì)于TCP non-blocking socket, recv返回值== -1,但是errno == EAGAIN, 此時(shí)表示在執(zhí)行recv時(shí)相應(yīng)的socket buffer中沒有數(shù)據(jù),應(yīng)該繼續(xù)recv。

            【If no messages are available at the socket and O_NONBLOCK is not set on the socket's file descriptor, recv() shall block until a message arrives. If no messages are available at the socket and O_NONBLOCK is set on the socket's file descriptor, recv() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].】

            對(duì)于UDP recv 應(yīng)該一直讀取直到recv()==-1 && errno==EAGAIN,表示buffer中數(shù)據(jù)包被全部讀取。

             

             


                while(res != 0)
                {
                    
            //len = recv(sockfd, buff, MAXBUF, 0);


                    len =recv(sockfd, buff, 5, 0);
                    if(len < 0 ){
                        if(errno== EAGAIN){
                            printf("RE-Len:%d errno EAGAIN\n", len);
                            return 12;
                        }

                        if (errno == EINTR)

                           continue;          
                        perror("recv error\n");
                        break;
                    }elseif(len > 0){
                        printf("Recved:%s, and len is:%d \n", buff, len);
                        len =send(sockfd, buff, len, 0);/* if the client socket was closed and the socketfd here in kernel has set the status as RST this process will recv a SIGPIPE, and the process will exit if we don't handle it to SIGING */
                        if(len < 0){
                            perror("send error");
                            return-1;
                        }
                        memset(buff, 0, MAXBUF);
                        continue;
                    }else{
            //==0

                        printf("Disconnected by peer!\n");
                        res = 0;
                    }
                }



            外記:
            accetp()是慢系統(tǒng)調(diào)用,在信號(hào)產(chǎn)生時(shí)會(huì)中斷其調(diào)用并將errno變量設(shè)置為EINTR,此時(shí)應(yīng)重新調(diào)用accept()。
            所以使用時(shí)應(yīng)這樣:


             while(1){
              if((connfd =accept(....))==-1 ){
              if(errno== EINTR)
              continue;
              perror("accept()");
              exit(1);
              }


              /* do sth with "connfd" */
              }



            signal 與 sigaction 區(qū)別:
                signal函數(shù)每次設(shè)置具體的信號(hào)處理函數(shù)(非SIG_IGN)只能生效一次,每次在進(jìn)程響應(yīng)處理信號(hào)時(shí),隨即將信號(hào)處理函數(shù)恢復(fù)為默認(rèn)處理方式.所以如果想多次相同方式處理某個(gè)信號(hào),通常的做法是,在響應(yīng)函數(shù)開始,再次調(diào)用signal設(shè)置。

            int sig_int();//My signal handler

                ...
                signal(SIGINT, sig_int);
                ...

            int sig_int()
            {

               signal(SIGINT, sig_int);
                ....
            }

            這種代碼段的一個(gè)問題是:在信號(hào)發(fā)生之后到信號(hào)處理程序中調(diào)用s i g n a l函數(shù)之間有一個(gè)
            時(shí)間窗口。在此段時(shí)間中,可能發(fā)生另一次中斷信號(hào)。第二個(gè)信號(hào)會(huì)造成執(zhí)行默認(rèn)動(dòng)作,而對(duì)
            中斷信號(hào)則是終止該進(jìn)程。這種類型的程序段在大多數(shù)情況下會(huì)正常工作,使得我們認(rèn)為它們
            正確,而實(shí)際上卻并不是如此。
            另一個(gè)問題是:在進(jìn)程不希望某種信號(hào)發(fā)生時(shí),它不能關(guān)閉該信號(hào)

            sigaction:
            1.在信號(hào)處理程序被調(diào)用時(shí),系統(tǒng)建立的新信號(hào)屏蔽字會(huì)自動(dòng)包括正被遞送的信號(hào)。因此保證了在處理一個(gè)
            給定的信號(hào)時(shí),如果這種信號(hào)再次發(fā)生,那么它會(huì)被阻塞到對(duì)前一個(gè)信號(hào)的處理結(jié)束為止
            2.響應(yīng)函數(shù)設(shè)置后就一直有效,不會(huì)重置
            3.對(duì)除S I G A L R M以外的所有信號(hào)都企圖設(shè)置S A _ R E S TA RT標(biāo)志,于是被這些信號(hào)中斷
            的系統(tǒng)調(diào)用(read,write)都能自動(dòng)再起動(dòng)。不希望再起動(dòng)由S I G A L R M信號(hào)中斷的系統(tǒng)調(diào)用的原因是希望對(duì)I / O操作可以設(shè)置時(shí)間限制。
             
            所以希望能用相同方式處理信號(hào)的多次出現(xiàn),最好用sigaction.信號(hào)只出現(xiàn)并處理一次,可以用signal

            posted on 2011-11-05 01:13 大龍 閱讀(2292) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久这里只精品99re66| 色综合久久中文综合网| 亚洲综合精品香蕉久久网97| 伊人久久大香线蕉综合影院首页| 国产精品一区二区久久精品无码 | 国产精品亚洲美女久久久| 亚洲香蕉网久久综合影视| 国内精品伊人久久久久妇| 久久国产视频99电影| 激情五月综合综合久久69| 伊人久久精品无码av一区| 伊人色综合久久天天人手人婷| 一个色综合久久| 亚洲天堂久久久| 无码国内精品久久人妻蜜桃 | 久久综合亚洲鲁鲁五月天| 国内精品久久久久影院薰衣草 | 欧美大香线蕉线伊人久久| 久久夜色精品国产噜噜噜亚洲AV| 久久婷婷五月综合国产尤物app | 无码精品久久久久久人妻中字| 色综合久久久久无码专区| 久久免费高清视频| 日韩欧美亚洲综合久久影院Ds | 99久久做夜夜爱天天做精品| 性色欲网站人妻丰满中文久久不卡| 久久精品人人做人人爽97| 国产一区二区三区久久| 久久久久女教师免费一区| 久久久久波多野结衣高潮| 久久久久综合网久久| 久久精品中文字幕大胸| 丰满少妇人妻久久久久久| 久久人妻少妇嫩草AV无码蜜桃| 国产99久久久国产精品小说| 国产亚洲美女精品久久久久狼| 久久夜色精品国产亚洲av| 久久久噜噜噜久久中文福利| 久久强奷乱码老熟女| 狠狠88综合久久久久综合网| 伊人色综合久久天天网|