青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Prayer

在一般中尋求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

SIGPIPE導致的程序退出

Posted on 2009-04-29 16:59 Prayer 閱讀(647) 評論(0)  編輯 收藏 引用 所屬分類: SOCKET

當服務器close一個連接時,若client端接著發數據。根據TCP協議的規定,會收到一個RST響應,client再往這個服務器發送數據時,系統會發出一個SIGPIPE信號給進程,告訴進程這個連接已經斷開了,不要再寫了。
    根據信號的默認處理規則SIGPIPE信號的默認執行動作是terminate(終止、退出),所以client會退出。若不想客戶端退出可以把SIGPIPE設為SIG_IGN

    如:    signal(SIGPIPE,SIG_IGN);
    這時SIGPIPE交給了系統處理。

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


http://www.cublog.cn/u/31357/showart_242605.html


好久沒做過C開發了,最近重操舊業。
聽說另外一個項目組socket開發遇到問題,發送端和接受端數據大小不一致。建議他們采用writen的重發機制,以避免信號中斷錯誤。采用后還是有問題。PM讓我幫忙研究下。
UNP n年以前看過,很久沒做過底層開發,手邊也沒有UNP vol1這本書,所以做了個測試程序,研究下實際可能發生的情況了。

測試環境:AS3和redhat 9(缺省沒有nc)

先下載unp源碼:
wget http://www.unpbook.com/unpv13e.tar.gz
tar xzvf *.tar.gz;
configure;make lib.
然后參考str_cli.c和tcpcli01.c,寫了測試代碼client.c

#include    "unp.h"

#define MAXBUF 40960
void processSignal(int signo)
{
    printf("Signal is %d\n", signo);
    signal(signo, processSignal);
}
void
str_cli(FILE *fp, int sockfd)
{
    char    sendline[MAXBUF], recvline[MAXBUF];

    while (1) {

        memset(sendline, 'a', sizeof(sendline));
        printf("Begin send %d data\n", MAXBUF);
        Writen(sockfd, sendline, sizeof(sendline));
        sleep(5);

    }
}

int
main(int argc, char **argv)
{
    int                    sockfd;
    struct sockaddr_in    servaddr;

    signal(SIGPIPE, SIG_IGN);
    //signal(SIGPIPE, processSignal);

    if (argc != 2)
        err_quit("usage: tcpcli [port]");

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(argv[1]));
    Inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

    str_cli(stdin, sockfd);        /* do it all */

    exit(0);
}

 

 

為了方便觀察錯誤輸出,lib/writen.c也做了修改,加了些日志:

 

 

/* include writen */
#include    "unp.h"

ssize_t        &nbs

p;               /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
    size_t         nleft;
     ssize_t         nwritten;
    const char    *ptr;

     ptr = vptr;
     nleft = n;
    while (nleft > 0) {
        printf("Begin Writen %d\n", nleft);
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR) {
                printf("intterupt\n");
                 nwritten = 0;        /* and call write() again */
            }
            else
                return(-1);            /* error */
        }

         nleft -= nwritten;
         ptr += nwritten;
        printf("Already write %d, left %d, errno=%d\n", nwritten, nleft, errno);
    }
    return(n);
}
/* end writen */

void
Writen(int fd, void *ptr, size_t nbytes)
{
    if (writen(fd, ptr, nbytes) != nbytes)
         err_sys("writen error");
}

 

client.c放在tcpclieserv目錄下,修改了Makefile,增加了client.c的編譯目標

 


client: client.c
                 ${CC} ${CFLAGS} -o $@ $< ${LIBS}

 

接著就可以開始測試了。

測試1 忽略SIGPIPE信號,writen之前,對方關閉接受進程

本機服務端:


nc -l -p 30000

本機客戶端:
./client 30000
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
執行到上步停止服務端,client會繼續顯示:
Begin send 40960 data
Begin Writen 40960
writen error: Broken pipe(32)
結論:可見write之前,對方socket中斷,發送端write會返回-1,errno號為EPIPE(32)

測試2 catch SIGPIPE信號,writen之前,對方關閉接受進程

修改客戶端代碼,catch sigpipe信號

        //signal(SIGPIPE, SIG_IGN);

        signal(SIGPIPE, processSignal);

本機服務端:


nc -l -p 30000

本機客戶端:
make client
./client 30000

Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
執行到上步停止服務端,client會繼續顯示:
Begin send 40960 data
Begin Writen 40960
Signal is 13
writen error: Broken pipe(32)
結論:可見write之前,對方socket中斷,發送端write時,會先調用SIGPIPE響應函數,然后write返回-1,errno號為EPIPE(32)

測試3 writen過程中,對方關閉接受進程

為了方便操作,加大1次write的數據量,修改MAXBUF為4096000

本機服務端:


nc -l -p 30000

本機客戶端:
make client
./client 30000

Begin send 4096000 data
Begin Writen 4096000
執行到上步停止服務端,client會繼續顯示:
Already write 589821, left 3506179, errno=0
Begin Writen 3506179
writen error: Connection reset by peer(104)

結論:可見socket write中,對方socket中斷,發送端write會先返回已經發送的字節數,再次write時返回-1,errno號為ECONNRESET(104)

為什么以上測試,都是對方已經中斷socket后,發送端再次write,結果會有所不同呢。從后來找到的UNP5.12,5.13能找到答案

The client's call to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline.

以上解釋了測試3的現象,write時,收到RST.

What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.

The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.

If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.

以上解釋了測試1,2的現象,write一個已經接受到RST的socket,系統內核會發送SIGPIPE給發送進程,如果進程catch/ignore這個信號,write都返回EPIPE錯誤.

因此,UNP建議應用根據需要處理SIGPIPE信號,至少不要用系統缺省的處理方式處理這個信號,系統缺省的處理方式是退出進程,這樣你的應用就很難查處處理進程為什么退出。


http://blog.csdn.net/shcyd/archive/2006/10/28/1354577.aspx

在Unix系統下,如果send在等待協議傳送數據時網絡斷開的話,調用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。
在Unix系統下,如果recv函數在等待協議接收數據時網絡斷開了,那么調用recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

處理方法:
在初始化時調用signal(SIGPIPE,SIG_IGN)忽略該信號(只需一次)
其時send或recv函數將返回-1,errno為EPIPE,可視情況關閉socket或其他處理

gdb:
gdb默認收到sigpipe時中斷程序,可調用handle SIGPIPE nostop print

相關

(1)SIG_DFL信號專用的默認動作:
  (a)如果默認動作是暫停線程,則該線程的執行被暫時掛起。當線程暫停期間,發送給線程的任何附加信號都不交付,直到該線程開始執行,但是SIGKILL除外。
  (b)把掛起信號的信號動作設置成SIG_DFL,且其默認動作是忽略信號 (SIGCHLD)。

(2)SIG_IGN忽略信號
  (a)該信號的交付對線程沒有影響
  (b)系統不允許把SIGKILL或SIGTOP信號的動作設置為SIG_DFL

(3)指向函數的指針--捕獲信號
  (a)信號一經交付,接收線程就在指定地址上執行信號捕獲程序。在信號捕 獲函數返回后,接受線程必須在被中斷點恢復執行。
  (b)用C語言函數調用的方法進入信號捕捉程序:
    void func (signo)
    int signo;
    func( )是指定的信號捕捉函數,signo是正被交付信號的編碼
  (c)如果SIGFPE,SIGILL或SIGSEGV信號不是由C標準定義的kill( )或raise( )函數所生成,則從信號SIGFPE,SIGILL,SIGSEGV的信號捕獲函數正常返回后線程的行為是未定義的。
  (d)系統不允許線程捕獲SIGKILL和SIGSTOP信號。
  (e)如果線程為SIGCHLD信號建立信號捕獲函數,而該線程有未被等待的以終止的子線程時,沒有規定是否要生成SIGCHLD信號來指明那個子線程。

每一種信號都被OSKit給予了一個符號名,對于32位的i386平臺而言,一個字32位,因而信號有32種。下面的表給出了常用的符號名、描述和它們的信號值。

符號名  信號值 描述                是否符合POSIX
SIGHUP  1   在控制終端上檢測到掛斷或控制線程死亡  是
SIGINT  2   交互注意信號              是
SIGQUIT  3   交互中止信號              是
SIGILL  4   檢測到非法硬件的指令          是
SIGTRAP  5   從陷阱中回朔              否
SIGABRT  6   異常終止信號              是
SIGEMT  7   EMT 指令                否
SIGFPE  8   不正確的算術操作信號          是
SIGKILL  9   終止信號                是
SIGBUS  10   總線錯誤                否
SIGSEGV  11   檢測到非法的內存調用          是
SIGSYS  12   系統call的錯誤參數           否
SIGPIPE  13   在無讀者的管道上寫           是
SIGALRM  14   報時信號                是
SIGTERM  15   終止信號                是
SIGURG  16   IO信道緊急信號             否
SIGSTOP  17   暫停信號                是
SIGTSTP  18   交互暫停信號              是
SIGCONT  19   如果暫停則繼續             是
SIGCHLD  20   子線程終止或暫停            是
SIGTTIN  21   后臺線程組一成員試圖從控制終端上讀出  是
SIGTTOU  22   后臺線程組的成員試圖寫到控制終端上   是
SIGIO   23   允許I/O信號               否
SIGXCPU  24   超出CPU時限               否
SIGXFSZ  25   超出文件大小限制            否
SIGVTALRM 26   虛時間警報器              否
SIGPROF  27   側面時間警報器             否
SIGWINCH 28   窗口大小的更改             否
SIGINFO  29   消息請求                否
SIGUSR1  30   保留作為用戶自定義的信號1        是
SIGUSR2  31   保留作為用戶自定義的信號        是

注意:Linux信號機制基本上是從Unix系統中繼承過來的。早期Unix系統中的信號機制比較簡單和原始,后來在實踐中暴露出一些問題,因此,把那些建立在早期機制上的信號叫做"不可靠信號",信號值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32,SIGRTMAX=63)的信號都是不可靠信號。這就是"不可靠信號"的來源。它的主要問題是:進程每次處理信號后,就將對信號的響應設置為默認動作。在某些情況下,將導致對信號的錯誤處理;因此,用戶如果不希望這樣的操作,那么就要在信號處理函數結尾再一次調用signal(),重新安裝該信號。


 

另外,我再做一些補充,產生RST響應以至于系統發出SIGPIPE信號,應該分為兩種情況:

1. 客戶端到服務端之間網絡斷掉,或者服務端斷電等,物理連接斷掉了,這種情況下客戶端不會退出,send函數正常執行,不會感覺到自己出錯。因為由于物理網絡斷開,服務端不會給客戶端回應錯誤消息,沒有RST響應,自然也不會產生SIGPIPE信號。但是當服務端再恢復正常的時候,對客戶端send來的消息會產生RST響應,客戶端就收到SIGPIPE信號了,程序退出,但是這時send函數是能夠返回 -1的。可以進行異常處理。

2.客戶端到服務端的網絡能通,服務程序掛掉,客戶端程序會馬上退出,因為服務端能正常返回錯誤消息,客戶端收到,SIGPIPE信號就產生了。不過我不確定此時服務端返回是的RST響應,抓包來看沒有RST標志。水平有限,只寫到這了。


文章出處:http://www.diybl.com/course/6_system/linux/Linuxjs/20081020/150832.html

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美一级电影久久| 麻豆成人在线观看| 国自产拍偷拍福利精品免费一| 欧美成人在线免费观看| 欧美在线地址| 久久人人97超碰国产公开结果 | 久久婷婷蜜乳一本欲蜜臀| 先锋影音一区二区三区| 性久久久久久久久| 久久综合激情| 欧美午夜不卡视频| 国产视频久久久久| 91久久久一线二线三线品牌| 99精品国产在热久久下载| 一区二区欧美日韩| 欧美一区二区三区视频在线观看| 久久久91精品国产一区二区精品| 美玉足脚交一区二区三区图片| 亚洲电影免费在线| 亚洲成人自拍视频| 亚洲一区二区在线观看视频| 午夜日韩视频| 亚洲夫妻自拍| 国产精品欧美日韩| 尤物九九久久国产精品的分类| 亚洲青涩在线| 午夜精品久久久久久99热| 久久久久久久久久看片| 亚洲激情偷拍| 欧美一级在线视频| 国语自产精品视频在线看一大j8 | 久久精品欧美| 欧美大色视频| 亚洲在线视频免费观看| 免费观看成人www动漫视频| 欧美视频久久| 亚洲精品中文字幕女同| 欧美伊久线香蕉线新在线| 欧美a级片网| 亚洲欧美日韩高清| 欧美精品电影| 亚洲大胆人体视频| 欧美一区二区国产| 一本色道久久综合一区| 欧美成人免费在线视频| 黄色工厂这里只有精品| 性色av一区二区三区在线观看| 亚洲欧洲日本mm| 欧美aⅴ一区二区三区视频| 国产视频观看一区| 亚洲一区二区三区视频| 亚洲国产成人精品久久久国产成人一区| 西瓜成人精品人成网站| 国产精品国产三级国产普通话三级| 亚洲国产精品传媒在线观看| 久久久久欧美精品| 欧美在线播放一区| 黄色亚洲大片免费在线观看| 欧美有码视频| 欧美亚洲系列| 国产最新精品精品你懂的| 欧美专区福利在线| 午夜激情综合网| 国产日韩亚洲欧美综合| 久久av一区二区三区| 午夜一区二区三视频在线观看| 国产精品欧美日韩久久| 午夜精品亚洲| 性欧美激情精品| 国产日韩av在线播放| 欧美一级网站| 久久精品视频在线免费观看| 国内揄拍国内精品久久| 久久人人爽人人爽爽久久| 久久国产一二区| 亚洲电影在线播放| 亚洲国产片色| 国产精品美女午夜av| 久久国产精品色婷婷| 欧美一区二区三区久久精品茉莉花 | 国产日本欧洲亚洲| 久久成人18免费观看| 久久精品在线观看| 亚洲精品久久久久| 亚洲素人在线| 1024日韩| 亚洲深夜激情| 狠狠色伊人亚洲综合成人| 欧美/亚洲一区| 欧美日本国产在线| 羞羞答答国产精品www一本 | 久久久青草婷婷精品综合日韩| 久久久久久久一区二区| 亚洲精品国偷自产在线99热| 99综合电影在线视频| 国产美女精品在线| 欧美激情二区三区| 国产人妖伪娘一区91| 欧美黑人国产人伦爽爽爽| 欧美午夜精品久久久久久超碰| 久久久久久久91| 欧美日韩在线播放三区四区| 欧美一区视频在线| 欧美高清视频一区| 久久人人97超碰精品888| 欧美日韩专区| 欧美激情区在线播放| 国产精品揄拍一区二区| 亚洲高清视频在线观看| 国产欧美一区二区白浆黑人| 亚洲国产精品久久91精品| 国产午夜精品一区二区三区视频| 亚洲国产日韩欧美| 伊人精品成人久久综合软件| 亚洲图片欧洲图片日韩av| 亚洲日本成人女熟在线观看| 午夜精品久久久久影视 | 久久久久国产精品www| 亚洲一区二区免费看| 牛牛精品成人免费视频| 久久精品视频在线看| 国产精品美腿一区在线看| 亚洲国产日韩精品| 在线观看免费视频综合| 亚洲欧美一级二级三级| 亚洲性图久久| 欧美日韩福利| 亚洲欧洲日本国产| 日韩网站在线| 欧美另类极品videosbest最新版本| 麻豆亚洲精品| 在线不卡中文字幕| 一区二区冒白浆视频| 欧美激情1区| 在线播放中文一区| 久久青草久久| 欧美电影美腿模特1979在线看| 国一区二区在线观看| 久久国内精品视频| 美女精品网站| 最新成人av网站| 欧美激情一区| 一本色道久久综合亚洲精品不卡| 亚洲深夜福利| 欧美午夜精品理论片a级大开眼界| 亚洲人成在线播放网站岛国| 日韩亚洲成人av在线| 欧美片第一页| 一区二区三区高清| 欧美亚洲色图校园春色| 国产视频一区在线观看一区免费| 亚洲欧美国产三级| 久久久久久久久综合| 激情综合自拍| 欧美国产视频在线| 99精品视频免费| 午夜精彩视频在线观看不卡 | 在线不卡中文字幕播放| 狼狼综合久久久久综合网| 亚洲高清av在线| 亚洲私人影院在线观看| 国产精品毛片va一区二区三区| 欧美一区二区成人| 亚洲国产成人精品久久久国产成人一区| 制服丝袜激情欧洲亚洲| 国产亚洲va综合人人澡精品| 美女主播视频一区| 中日韩美女免费视频网站在线观看| 欧美制服丝袜第一页| 亚洲精品小视频在线观看| 欧美三区美女| 久久久蜜桃一区二区人| 亚洲黄色小视频| 久久www成人_看片免费不卡| 亚洲国产成人一区| 国产精品高潮粉嫩av| 久久精品国产99国产精品| 欧美激情第8页| 久久久一本精品99久久精品66| 亚洲看片免费| 国内精品久久国产| 欧美网站大全在线观看| 卡通动漫国产精品| 小嫩嫩精品导航| 99亚洲一区二区| 亚洲观看高清完整版在线观看| 先锋影音国产一区| 亚洲最新色图| 1204国产成人精品视频| 国产精品久久久一区麻豆最新章节 | 亚洲午夜精品国产| 亚洲大片在线观看| 久久精品九九| 亚洲免费视频中文字幕| 亚洲国产日韩欧美一区二区三区| 国产欧美日韩一区| 亚洲大黄网站| 在线欧美日韩精品| 国产欧美日韩在线观看| 欧美日韩亚洲一区二区三区在线 |