在杀死我的TCP / IP连接后使用POSIX“写入”功能会崩溃我的应用程序 - 为什么?

时间:2017-05-01 22:03:06

标签: c sockets tcp posix

我正在开发一个使用POSIX TCP / IP功能与服务器通信的C应用程序。我正在进行一些测试,看看当连接意外关闭时应用程序如何响应。

主要的工作室功能如下所示:

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

当我与服务器建立良好连接时,此功能可以正常工作。但是,在终止连接后调用此函数会导致我的应用程序崩溃。

理想情况下,我希望write函数返回一个错误,指示写入失败。这将允许我处理错误并将我的程序转换到适当的状态。但是,这不是发生的事情。

我很好奇为什么这个函数调用会使应用程序崩溃。我有点认为这可能是函数调用没有锁定的问题,然后它引用的指针变得“坏”,导致分段错误。

以下是我配置套接字的方法:

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

任何帮助将不胜感激

1 个答案:

答案 0 :(得分:1)

除了提到的遗漏错误检查@RemyLebeau之外,您也没有错误检查write()本身:

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

这里你忽略了它返回-1的可能性,在这种情况下你应该调用perror()或用strerror()构造一个错误消息字符串并打印它,关闭套接字,告诉来电者他没有继续写作。

您还需要将SIGPIPE设置为SIG_IGNORE或其他任何内容,以便EPIPE写入错误不会导致SIGPIPE信号。

所有这些ERR_NET_COULD_NOT_GET_SOCKET_OPTION的东西都很糟糕。您应该返回实际的errno值,或者至少打印它,而不仅仅是在getsockopt()情况下,而是在所有错误情况下。

你正在以阻止模式进行connect()。因此,以下select()完全没有意义。