多个线程都在不间断的连接不同的主机,然后发生连接超时,显然没有死锁。另外,我用一个线程依次连接不同主机时,程序运行到某个时候,也发生和多线程类似的问题。以下是我的程序连接代码:void PlainSocketImpl::connectToAddress(InetAddress pAddress, int port, size_t timeoutMS) {// // create and initialize a sockaddr_in structure // specifying the requested port. // struct sockaddr_in sa; ::memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); // convert port to network byte order ::memcpy(&sa.sin_addr, pAddress.getAddress(), pAddress.getAddressLength());// // If a timeout value has been specified, then we need to set the socket // non-blocking // bool oldBlocking = m_bBlocking; if(timeoutMS != 0) { setBlocking(false); }// // Call ::connect() to create the socket connection. // ::connect() will return zero is successful, otherwise -1. // // The WIN32 documentation recommends comparing the return value // against the manifest constant SOCKET_ERROR, but as this is not // mandatory, we will use the portable test of < 0. // if(::connect(m_rpSocketDescriptor->getFD(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(struct sockaddr_in)) < 0) { int errorNum = NetUtils::GetLastSocketError(); bool bConnected = false; // // If we have set the socket non-blocking (due to a timeout being specified) // then we can expect the connect() to fail with EINPROGRESS. In this case // we must perform a select() to wait for the command's completion. // if(!m_bBlocking && errorNum == EINPROGRESS) { // select for readability or writability if(NetUtils::SelectSocket(m_rpSocketDescriptor, timeoutMS, true, true)) { // // The select succeeded, but this may be due to an error // on the socket. This can be established using ::getsockopt // (there are other ways, but this is the Stevens method) // // Note: for Solaris portability reasons, we do not call // getIntOption, but call getsockopt directly // int error = 0; cel_socklen_t retLen = sizeof(error); if(::getsockopt(m_rpSocketDescriptor->getFD(), SOL_SOCKET, SO_ERROR, (char*)&error, &retLen) < 0) { error = errno; }
if(error) { // If an error has occured then we treat it the same way whether or // not there is a timeout value. For this reason we just set the // errorNum and allow the code to fall-through to the next section // where an appropriate exception is thrown. errorNum = error; } else { // Great! The select() succeeded and the socket has no error // condition, this means that it is now connected okay. bConnected = true; } } else { static const String err(_T("Connection timed out")); throw SocketTimeoutException(err); } }
int port, size_t timeoutMS)
{//
// create and initialize a sockaddr_in structure
// specifying the requested port.
//
struct sockaddr_in sa;
::memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port); // convert port to network byte order
::memcpy(&sa.sin_addr, pAddress.getAddress(), pAddress.getAddressLength());//
// If a timeout value has been specified, then we need to set the socket
// non-blocking
//
bool oldBlocking = m_bBlocking;
if(timeoutMS != 0)
{
setBlocking(false);
}//
// Call ::connect() to create the socket connection.
// ::connect() will return zero is successful, otherwise -1.
//
// The WIN32 documentation recommends comparing the return value
// against the manifest constant SOCKET_ERROR, but as this is not
// mandatory, we will use the portable test of < 0.
//
if(::connect(m_rpSocketDescriptor->getFD(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(struct sockaddr_in)) < 0)
{
int errorNum = NetUtils::GetLastSocketError();
bool bConnected = false; //
// If we have set the socket non-blocking (due to a timeout being specified)
// then we can expect the connect() to fail with EINPROGRESS. In this case
// we must perform a select() to wait for the command's completion.
//
if(!m_bBlocking && errorNum == EINPROGRESS)
{
// select for readability or writability
if(NetUtils::SelectSocket(m_rpSocketDescriptor, timeoutMS, true, true))
{
//
// The select succeeded, but this may be due to an error
// on the socket. This can be established using ::getsockopt
// (there are other ways, but this is the Stevens method)
//
// Note: for Solaris portability reasons, we do not call
// getIntOption, but call getsockopt directly
//
int error = 0;
cel_socklen_t retLen = sizeof(error); if(::getsockopt(m_rpSocketDescriptor->getFD(), SOL_SOCKET, SO_ERROR, (char*)&error, &retLen) < 0)
{
error = errno;
}
if(error)
{
// If an error has occured then we treat it the same way whether or
// not there is a timeout value. For this reason we just set the
// errorNum and allow the code to fall-through to the next section
// where an appropriate exception is thrown. errorNum = error;
}
else
{
// Great! The select() succeeded and the socket has no error
// condition, this means that it is now connected okay.
bConnected = true;
}
}
else
{
static const String err(_T("Connection timed out"));
throw SocketTimeoutException(err);
}
}
if(!bConnected)
{
// ... and throw an appropriate exception
String errMsg = NetUtils::GetSocketErrorString(errorNum);
errMsg += _T(" for: ");
errMsg += pAddress.getHostName(); if(errorNum == ENETUNREACH || errorNum == EHOSTUNREACH)
{
throw NoRouteToHostException(errMsg);
}
else
{
throw ConnectException(errMsg);
}
}
}