2017-05-01 16 views
0

我正在使用POSIX TCP/IP函數與服務器進行通信的C應用程序。我正在做一些測試,看看應用程序在連接意外關閉時如何響應。殺死我的TCP/IP連接後使用POSIX「寫」功能崩潰我的應用程序 - 爲什麼?

主要習藝功能如下所示:

uint32_t netWriteMsg(uint8_t * pmsg, size_t msg_size) 
{ 
    if(write(m_sockfd, pmsg, msg_size) < msg_size) 
     return ERR_NET_NOT_ALL_BYTES_SENT; 

    return ERR_NONE; 
} 

此功能按預期工作時,我有與服務器的連接良好。但是,在終止連接後調用這個函數會使我的應用程序崩潰。

理想情況下,我希望寫函數返回一個錯誤,指出寫入失敗。這將允許我處理錯誤並將我的程序轉換到適當的狀態。但是,這不是發生了什麼。

我很好奇爲什麼這個函數調用會導致應用程序崩潰。我有些想,這可能是一個問題,其中函數調用沒有鎖定,然後它的引用指針變成'壞',導致分段錯誤。

這是我如何配置我的插座:

uint32_t netConnect() 
{ 
    /* locals */ 
    struct sockaddr_in serv_addr; 
    fd_set fdset_sock; // only 1 file descriptor (socket fd) will be placed in this set 
    fd_set fdset_empty; 
    struct timeval time = {NET_TIMEOUT_CONNECT, 0}; 
    int sock_error; 
    socklen_t optlen; 
    int error = ERR_NONE; 

    /* obtain socket file descriptor and set it to non-blocking */ 
    m_sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    memset(&serv_addr, 0, sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT_NO); 
    inet_pton(AF_INET, IP_ADDR, &(serv_addr.sin_addr.s_addr)); 


    /* attempt to connect */ 
    error = connect(m_sockfd, &serv_addr, sizeof(serv_addr)); 
    if(error) return ERR_NET_CONNECT_FAILED_IMMEDIATELY; 

    select(m_sockfd, &fdset_empty, &fdset_sock, &fdset_empty, &time); // blocks until socket is good or timeout occured 
    error = getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &sock_error, &optlen); 
    if(error) return ERR_NET_COULD_NOT_GET_SOCKET_OPTION; 

    if(sock_error) 
     return ERR_NET_CONNECT_ATTEMPT_TIMEOUT; 

    m_is_connected = 1; 

    return ERR_NONE;   
} 

任何幫助,將不勝感激

+5

如果沒有接收者進行寫入調用,那麼您的進程應該被SIGPIPE殺死。將信號的信號處理設置爲SIG_IG,並且您應該開始獲取EPIPE errno錯誤代替信號。 – PSkocik

+1

你在'socket()'或'select()'上根本沒有做任何錯誤檢查,而你在connect()方面的錯誤檢查是錯誤的。如果'm_sockfd'是非阻塞的,'connect()'將返回-1,'errno'將是'EINPROGRESS'。在返回'ERR_NET_CONNECT_FAILED_IMMEDIATELY'之前,您需要檢查。並且檢索'SO_ERROR'只是有一個錯誤代碼才能檢索,所以在調用'getsockopt()'之前確保'select()'成功。 –

+2

@PSkocik:其他選項包括1)使用'send()'而不是'write()',這樣你就可以指定'MSG_NOSIGNAL'標誌,和/或2)使用'setsockopt()'啓用'SO_NOSIGPIPE'選項。在支持這些選項的平臺上,就是這樣。 –

回答

1

繼缺少的錯誤檢查@RemyLebeau提到的,你也沒有錯誤校驗的write()本身:

if(write(m_sockfd, pmsg, msg_size) < msg_size) 
    return ERR_NET_NOT_ALL_BYTES_SENT; 

這裏你忽略了它返回-1 possibilty,在這種情況下,你應該叫perror()或建造n錯誤信息字符串strerror()並打印出來,關閉插座,告訴來電者,以免他不斷寫信。

您還需要將SIGPIPE設置爲SIG_IGNORE或其它類型,以便EPIPE寫入錯誤不會導致SIGPIPE信號。

而這一切ERR_NET_COULD_NOT_GET_SOCKET_OPTION的東西是不好的做法。您應該返回實際的errno值,或者至少將其打印出來,而不僅僅是在getsockopt()的情況下,但在所有錯誤情況下。

而你正在阻止模式下執行connect()。因此以下select()是完全沒有意義的。

相關問題