1、INVALID_SOCKET : 表示该 socket fd 无效。如 accept(2) 或 socket(2) 等在创建socketfd时:
int m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET){
printf("socket failed, err_code=%d\n", _GetErrorCode());
return NETLIB_ERROR;
}
2、SOCKET_ERROR : 如调用bind(2)、listen(2)、connect(2)、send(2)、setsockopt(2)、fcntl(2)等函数时出错则会返回该宏:
int ret = ::bind(m_socket, (sockaddr*)&serv_addr, sizeof(serv_addr));
if (ret == SOCKET_ERROR){
log("bind failed, err_code=%d", _GetErrorCode());
closesocket(m_socket);
return NETLIB_ERROR;
}
3、获取具体错误类型时使用 errno (注意多线程下它是不安全的):
int CBaseSocket::_GetErrorCode()
{
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
4、socket在非阻塞的情况下接收和发送数据时的错误码以及如何处理:
(1)判断socket是否“阻塞”(即检测错误类型 errno 是否为 EINPROGRESS 或 EWOULDBLOCK,该情况往往是由于TCP窗口导致的):
bool CBaseSocket::_IsBlock(int error_code)
{
#ifdef _WIN32
return ( (error_code == WSAEINPROGRESS) || (error_code == WSAEWOULDBLOCK) );
#else
return ( (error_code == EINPROGRESS) || (error_code == EWOULDBLOCK) );
#endif
}
此时需要具体逻辑去解决这个问题,防止内核缓冲区数据堆积无法接收或发送。
(2)若错误码 errno 为 EINTR(被信号中断了,则继续重试),则忽略该错误,继续接收或发送数据。
(3)若recv或send调用后返回 0 ,则表示对端关闭了连接。(此处还需要再深入去理解!)
while (true)
{
char recvbuf[32] = {0};
int ret = recv(clientfd, recvbuf, 32, 0);
if (ret > 0)
{
//收到了数据
std::cout << "recv successfully." << std::endl;
}
else if (ret == 0)
{
//对端关闭了连接
std::cout << "peer close the socket." << std::endl;
break;
}
else if (ret == -1)
{
if (errno == EWOULDBLOCK)
{
std::cout << "There is no data available now." << std::endl;
}
else if (errno == EINTR)
{
//如果被信号中断了,则继续重试recv函数
std::cout << "recv data interrupted by signal." << std::endl;
} else
{
//真的出错了
break;
}
}
}