我有一個共享多個線程的套接字連接池,一個死連接應該從池中刪除,問題是我不知道哪個死從SIGPIPE sighandler,在這種情況下的任何建議?在SIGPIPE清理
1
A
回答
5
解決此問題的一種方法是忽略SIGPIPE。這意味着您的寫入操作(write
,sendmsg
,無論什麼)都會返回一個錯誤,並且只要您注意錯誤返回,就會知道哪個文件描述符失敗 - 因爲所有內容都是同步的。
0
以下程序與套接字無關,而是使用命名管道。只是在這裏舉辦的程序,以演示我如何處理上述問題。它們是我爲了更好地理解命名管道而編寫的一對程序。處理所有錯誤條件。有兩個可執行文件必須單獨編譯。在同一臺PC上的兩個獨立終端中運行每個可執行文件。您運行它們的順序並不重要。無論哪個先運行,都會創建命名管道,另一個啓動時會注意到它已經創建(mkfifo錯誤處理)。每當read()返回時,寫入者每秒鐘都會向管道寫入一次,並且讀取器從管道中讀取數據。在作者方面,SIGPIPE被忽略,而是處理EPIPE。在兩個終端窗口(閱讀器或書寫器)中的任何一個的鍵盤上按'q',兩者都將退出。
如果不忽略SIGPIPE,會發生什麼情況是當我在寫入器之前退出讀取器(通過在讀取器終端中按q鍵)write()將失敗並觸發寫入器應用程序接收的SIGPIPE信號。這種默認行爲是立即退出應用程序。這當然不是我將要使用此代碼的多線程應用程序所需要的。所以我忽略了信號並檢查了errno並正確處理了它。
writer.c:
#include <stdio.h> //for printf()
#include <stdlib.h> //for malloc()
#include <stdint.h> //for definitions of uint8_t etc..
#include <unistd.h> //for sleep()
#include <sys/stat.h> //for S_IRUSR, S_IWUSR, mkfifo()
#include <fcntl.h> //for O_WRONLY
#include <errno.h> //for errno, perror()
#include "kbhit.h"
#include <sys/types.h>
#include <signal.h> //for signal()
/* Named pipe considerations (http://www.unixguide.net/unix/programming/2.10.3.shtml):
*
* To use the pipe, you open it like a normal file, and use read()
* and write() just as though it was a plain pipe.
* However, the open() of the pipe may block. The following rules apply:
*
* If you open for both reading and writing (O_RDWR), then the open will not block.
*
* If you open for reading (O_RDONLY), the open will block until
* another process opens the FIFO for writing, unless O_NONBLOCK is
* specified, in which case the open succeeds.
*
* If you open for writing O_WRONLY, the open will block until
* another process opens the FIFO for reading, unless O_NONBLOCK is
* specified, in which case the open fails.
*
* When reading and writing the FIFO, the same considerations apply as for
* regular pipes and sockets, i.e. read() will return EOF when all
* writers have closed, and write() will raise SIGPIPE when
* there are no readers. If SIGPIPE is blocked or ignored, the call
* fails with EPIPE.
*
*/
static const char file_path[] = "/tmp/anurag";
static const char message[] = "Hello from writer!";
int main(void) {
int ret;
int fd=0;
char keypress=0;
/*
* (http://stackoverflow.com/questions/4351989/cleanup-in-sigpipe)
* EPIPE is returned if fd is connected to a pipe or socket whose reading end is closed.
* When this happens the writing process will also receive a SIGPIPE signal.
* (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
*/
signal(SIGPIPE, SIG_IGN);
//Create the FIFO (named pipe)
ret = mkfifo(file_path, S_IRUSR | S_IWUSR);
if(ret == 0) {
printf("mkfifo(): Named pipe created.\n");
} else {
if ((ret == -1) && (errno == EEXIST)) {
perror("mkfifo()");
} else {
perror("mkfifo()");
}
}
printf("Will now begin waiting on open()...\n");
fd = open(file_path, O_WRONLY);
if(fd == -1) {
perror("open()");
} else if (fd > 0) {
printf("open(): Named pipe file descriptor opened for writing.\n");
}
while(keypress != 'q') {
if (kbhit()) {
keypress = getchar();
printf("Exiting...\n");
} else {
ret = write(fd, message, sizeof(message));
if(ret > 0) {
printf("write(): %d bytes to pipe: %s\n",ret,message);
} else if (ret <=0) {
if(errno == EPIPE) {
printf("write(): got EPIPE, reader closed the pipe, exiting...\n");
break;
} else {
perror("write()");
break;
}
}
}
sleep(1);
};
ret = close(fd);
if(ret == 0) {
printf("close(): Named pipe file descriptor closed.\n");
} else {
perror("close()");
}
ret = remove(file_path);
if(ret == 0) {
printf("remove(): Named pipe deleted.\n");
} else {
perror("remove()");
}
fflush(stdout);
fflush(stderr);
return EXIT_SUCCESS;
}
reader.c:
#include <stdio.h> //for printf()
#include <stdlib.h> //for malloc()
#include <stdint.h> //for definitions of uint8_t etc..
#include <unistd.h> //for sleep()
#include <sys/stat.h> //for S_IRUSR, S_IWUSR, mkfifo()
#include <fcntl.h> //for O_WRONLY
#include <errno.h> //for errno, perror()
#include <string.h> //for memset()
#include "kbhit.h"
/* Named pipe considerations (http://www.unixguide.net/unix/programming/2.10.3.shtml):
*
* To use the pipe, you open it like a normal file, and use read()
* and write() just as though it was a plain pipe.
* However, the open() of the pipe may block. The following rules apply:
*
* If you open for both reading and writing (O_RDWR), then the open will not block.
*
* If you open for reading (O_RDONLY), the open will block until
* another process opens the FIFO for writing, unless O_NONBLOCK is
* specified, in which case the open succeeds.
*
* If you open for writing O_WRONLY, the open will block until
* another process opens the FIFO for reading, unless O_NONBLOCK is
* specified, in which case the open fails.
*
* When reading and writing the FIFO, the same considerations apply as for
* regular pipes and sockets, i.e. read() will return EOF when all
* writers have closed, and write() will raise SIGPIPE when
* there are no readers. If SIGPIPE is blocked or ignored, the call
* fails with EPIPE.
*
*/
static const char file_path[] = "/tmp/anurag";
static char message[100] = {0};
int main(void) {
int ret;
int fd=0;
char keypress=0;
//Create the FIFO (named pipe)
ret = mkfifo(file_path, S_IRUSR | S_IWUSR);
if(ret == 0) {
printf("mkfifo(): Named pipe created.\n");
} else {
if ((ret == -1) && (errno == EEXIST)) {
perror("mkfifo()");
} else {
perror("mkfifo()");
}
}
printf("Will now begin waiting on open()...\n");
fd = open(file_path, O_RDONLY);
if(fd == -1) {
perror("open()");
} else if (fd > 0) {
printf("open(): Named pipe file descriptor opened for reading.\n");
}
while(keypress != 'q') {
if (kbhit()) {
keypress = getchar();
printf("Exiting...\n");
} else {
memset(message,0,100);
ret = read(fd, message, 100);
if(ret > 0) {
printf("read(): %d bytes from pipe: %s\n",ret, message);
} else if (ret == 0){
printf("read(): got EOF, writer closed the pipe, exiting...\n");
break;
} else if (ret < 0){
perror("read()");
break;
}
}
sleep(1);
};
ret = close(fd);
if(ret == 0) {
printf("close(): Named pipe file descriptor closed.\n");
} else {
perror("close()");
}
ret = remove(file_path);
if(ret == 0) {
printf("remove(): Named pipe deleted.\n");
} else {
perror("remove()");
}
fflush(stdout);
fflush(stderr);
return EXIT_SUCCESS;
}
上述兩個C文件利用的kbhit()的輪詢字符從所接收的鍵盤。下面是該代碼:
kbhit.c:
//Taken from: http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include "kbhit.h"
int kbhit(void) {
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if (ch != EOF) {
ungetc(ch, stdin);
return 1;
}
return 0;
}
kbhit.h:
#ifndef KBHIT_H_
#define KBHIT_H_
//Console related variables and functions
int kbhit(void);
#endif /* KBHIT_H_ */
相關問題
- 1. 處理SIGPIPE錯誤
- 2. 如何處理python中的破管(SIGPIPE)?
- 3. SIGPIPE的原因
- 4. SIGPIPE異常
- 5. Formview正在清理
- 6. 在pypy中清理
- 7. 清理我的清單
- 8. 在Xcode中清理/清理所有內容時運行腳本
- 9. 清理,如果在Haskell
- 10. NHibernate的ICurrentSessionContext正在清理
- 11. 在Makefile中遞歸清理
- 12. 在Rails中清理Markdown嗎?
- 13. ReSharper的:在代碼清理
- 14. 在html2txt後清理文本
- 15. 在android中清理SurfaceView
- 16. 在matlab中清理圖像
- 17. 在bash中清理$ PATH
- 18. 在Linux上清理echo $ PATH
- 19. 在Swift中清理AVCaptureSession
- 20. 在rails中清理jQuery
- 21. 清理系統在Linux
- 22. 在調用GetSystemMenu()後清理()
- 23. 在Ubuntu上清理python
- 24. 在C++中清理DirectX紋理
- 25. IOS - 與SIGPIPE信號功能和SIG_IGN
- 26. TCP客戶端服務器SIGPIPE
- 27. C#DataGridView清理
- 28. python github清理
- 29. UIPasteboard未清理
- 30. iphone - 清理Localizable.strings
正是我所要發佈。具體來說,如果你沒有忽略它,寫入操作會失敗,'errno'會被設置爲'EPIPE'。 – zwol 2010-12-04 04:53:06