我使用the following C++ code创建了一个TCP/IP客户端。在实际使用中,我在一个循环中使用它,并不断检查连接,直到服务器准备就绪。
在连接到服务器之前,这段代码会按顺序0.2、0.6、1循环。
在成功连接到服务器之后,什么都不会打印。没有错误被打印,几乎没有任何地方被传递。
如何知道TCP/IP连接是否成功?
int connect_timeout(int & socket, struct sockaddr * name, int namelen, timeval timeout)
{
unsigned long mode = 1;
int result= ioctlsocket(socket, FIONBIO, &mode);
if(NO_ERROR != result)
{
//std::cout << "0.0---------------" << std::endl;
return -1;
}
else
{
//std::cout << "0.1---------------" << std::endl;
}
result= connect(socket, name, namelen);
if(SOCKET_ERROR == result)
{
int errono = WSAGetLastError();
if(WSAEWOULDBLOCK == errono)
{
std::cout << "0.2---------------" << std::endl;
errono = 0;
}
else
{
//std::cout << "0.3---------------" << std::endl;
mode = 0;
ioctlsocket(socket, FIONBIO, &mode);
return -1;
}
}
else
{
std::cout << "0.4---------------" << std::endl;
}
mode = 0;
result= ioctlsocket(socket, FIONBIO, &mode);
if(0 < result)
{
//error
std::cout << "0.5---------------" << std::endl;
return -1;
}
else
{
std::cout << "0.6---------------" << std::endl;
}
fd_set readFd, writeFd, errFd;
FD_ZERO(&readFd);
FD_ZERO(&writeFd);
FD_ZERO(&errFd);
FD_SET(socket, &readFd);
FD_SET(socket, &writeFd);
FD_SET(socket, &errFd);
int sockNum = select(socket + 1, &readFd, &writeFd, &errFd, &timeout);
if(0 == sockNum)
{
//timeout
std::cout << "1---------------" << std::endl;
return -1;
}
else if(FD_ISSET(socket, &readFd) || FD_ISSET(socket, &writeFd) )
{
std::cout << "2---------------" << std::endl;
}
else
{
//error
std::cout << "3---------------" << std::endl;
return -1;
}
std::cout << "4---------------" << std::endl;
return 0;
}
1条答案
按热度按时间uujelgoq1#
connect()
documentation说道:使用非阻塞套接字,连接尝试不能立即完成。在这种情况下,connect将返回
SOCKET_ERROR
,WSAGetLastError
将返回WSAEWOULDBLOCK
。在这种情况下,有三种可能的情况:*使用
select
函数检查套接字是否可写,判断连接请求是否完成在连接尝试在非阻塞套接字上完成之前,在同一套接字上对
connect
的所有后续调用都将失败,并在连接成功完成时显示错误代码WSAEALREADY
和WSAEISCONN
。当连接已经挂起时从connect
返回的错误代码可能因实现而异。**因此,不建议应用程序使用对connect
的多个调用来检测连接完成。**如果它们这样做,它们必须准备以与处理WSAEALREADY
相同的方式处理WSAEINVAL
和WSAEWOULDBLOCK
误差值,以确保稳健的操作。...
对于面向连接的非阻塞套接字,通常不可能立即完成连接。在这种情况下,此函数返回错误
WSAEWOULDBLOCK
。但是,操作继续进行。当成功或失败结果变得已知时,可以通过两种方式之一来报告,这取决于客户端如何注册通知。
*如果客户端使用
select
函数,则在writefds
集合中报告成功,在exceptfds
集合中报告失败。select()
documentation说:参数
writefds
标识要检查可写性的套接字。如果套接字正在处理connect
调用(非阻塞),则在连接建立成功完成时套接字是可写的。...参数
exceptfds
标识要检查是否存在OOB数据或任何异常错误条件的套接字。注意:只有当选项
SO_OOBINLINE
为FALSE时,才会以这种方式报告带外数据。**如果套接字正在处理connect
调用(非阻塞),exceptfds
中指示连接尝试失败(然后应用程序必须调用getsockopt
SO_ERROR
来确定错误值,以描述发生故障的原因)。**本文档未定义将包括哪些其他错误。在调用
select()
之前,您关闭了套接字的非阻塞模式。您需要等待非阻塞connect()
操作完成,然后才能更改套接字的设置。尝试更像这样的东西: