2017-05-01 7 views
0

私はサーバーとの通信にPOSIX TCP/IP関数を使用するCアプリケーションを開発中です。現在、接続が予期せず終了したときにアプリケーションがどのように応答するかを確認するためにいくつかのテストを行っています。TCP/IP接続を終了した後にPOSIXの "write"関数を使用すると、アプリケーションがクラッシュします - なぜですか?

メイン労役場の機能を以下に示します。

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;   
} 

任意の助けが不足しているエラーチェック@RemyLebeauが言及にさらに

+5

書き込み呼び出しの受信者がいない場合、プロセスはSIGPIPEによって強制終了されるはずです。そのシグナルのシグナル処理をSIG_IGに設定してください。シグナルの代わりにEPIPEエラー番号を取得し始めるべきです。 – PSkocik

+1

'socket()'や 'select()'でエラーチェックをしていないので、 'connect()'のエラーチェックが間違っています。 'm_sockfd'が非ブロックの場合、' connect() 'は-1を返し、' errno'は 'EINPROGRESS'を返します。 'ERR_NET_CONNECT_FAILED_IMMEDIATELY'を返す前にそれをチェックする必要があります。 'SO_ERROR'の取得は、取得するエラーコードがある場合にのみ有効です。したがって、' getsockopt() 'を呼び出す前に' select() 'が成功していることを確認してください。 –

+2

@PSkocik:他のオプションには、1) 'write()'の代わりに 'send()'を使って 'MSG_NOSIGNAL'フラグを指定するか、' 2)setsockopt()を使って 'SO_NOSIGPIPE'オプション。これらのオプションをサポートするプラットフォームでは、つまり。 –

答えて

1

をいただければ幸い、あなたはまた、エラーチェックされていないwrite()自身を:

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

ここであなたがperror()を呼び出したり、構築する必要があり、その場合には、それは-1を返しpossibiltyを、無視していますn のエラーメッセージ文字列で、がソケットを閉じると、は書き込みをしないように呼び出し元に指示します。

また、EPIPE書き込みエラーによってSIGPIPE信号が発生しないように、SIGPIPEをSIG_IGNOREまたはそれ以外の値に設定する必要があります。

そして、このERR_NET_COULD_NOT_GET_SOCKET_OPTIONのすべてが悪い習慣です。 getsockopt()の場合だけでなく、すべてのエラーの場合、実際のerrnoの値を返すか、少なくとも印刷してください。

ブロックモードでconnect()を実行しています。したがって、次のselect()は完全に無意味です。

関連する問題