在终止我的 TCP/IP 连接后使用 POSIX "write" 函数会使我的应用程序崩溃 - 为什么?
Using the POSIX "write" function after killing my TCP/IP connection crashes my application - why?
我正在开发一个使用 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;
}
当我与服务器连接良好时,此功能按预期工作。但是,在终止连接后调用此函数会使我的应用程序崩溃。
理想情况下,我希望写入函数 return 指示写入失败的错误。这将允许我处理错误并将我的程序转换到适当的状态。然而,事实并非如此。
我很好奇为什么这个函数调用会导致应用程序崩溃。我有点想这可能是函数调用没有锁定的问题,然后它引用的指针变成 'bad' 导致分段错误。
这是我配置套接字的方式:
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 之外,您也没有对 write()
本身进行错误检查:
if(write(m_sockfd, pmsg, msg_size) < msg_size)
return ERR_NET_NOT_ALL_BYTES_SENT;
在这里你忽略了它 returned -1 的可能性,在这种情况下你应该调用 perror()
或者用 strerror()
构造一个错误消息字符串并打印它,and 关闭套接字,and 告诉调用者不要继续写。
您还需要将 SIGPIPE 设置为 SIG_IGNORE 或其他任何值,以便 EPIPE 写入错误不会导致 SIGPIPE 信号。
所有这些 ERR_NET_COULD_NOT_GET_SOCKET_OPTION 都是糟糕的做法。您应该 return 实际 errno
值,或者至少打印它,不仅在 getsockopt()
情况下,而且在所有错误情况下。
并且您正在以阻塞模式执行 connect()
。因此,以下select()
完全没有意义。
我正在开发一个使用 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;
}
当我与服务器连接良好时,此功能按预期工作。但是,在终止连接后调用此函数会使我的应用程序崩溃。
理想情况下,我希望写入函数 return 指示写入失败的错误。这将允许我处理错误并将我的程序转换到适当的状态。然而,事实并非如此。
我很好奇为什么这个函数调用会导致应用程序崩溃。我有点想这可能是函数调用没有锁定的问题,然后它引用的指针变成 'bad' 导致分段错误。
这是我配置套接字的方式:
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 之外,您也没有对 write()
本身进行错误检查:
if(write(m_sockfd, pmsg, msg_size) < msg_size)
return ERR_NET_NOT_ALL_BYTES_SENT;
在这里你忽略了它 returned -1 的可能性,在这种情况下你应该调用 perror()
或者用 strerror()
构造一个错误消息字符串并打印它,and 关闭套接字,and 告诉调用者不要继续写。
您还需要将 SIGPIPE 设置为 SIG_IGNORE 或其他任何值,以便 EPIPE 写入错误不会导致 SIGPIPE 信号。
所有这些 ERR_NET_COULD_NOT_GET_SOCKET_OPTION 都是糟糕的做法。您应该 return 实际 errno
值,或者至少打印它,不仅在 getsockopt()
情况下,而且在所有错误情况下。
并且您正在以阻塞模式执行 connect()
。因此,以下select()
完全没有意义。