CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jul 2007
    Posts
    609

    Non blocking connect()

    I could have sworn I got this working at one point but I must of misplaced the code and I never added it to my socket class I use now instead of having to redo the whole socket handling each and every time.

    I got this part working:
    Code:
    		int flags = fcntl(sockfd,F_GETFL,0);
    		fcntl(sockfd,F_SETFL, flags | O_NONBLOCK);

    But there is a loop of some sort I have to do using Sleep() until I reach a certain amount of interations, and think I also have to use select() somewhere.

    I just can't seem to peiece it all together and online resources have not been very helpful and showing a complete program making use of this.

    Basically, I want connect() to timeout after like 5 seconds. By default it just sits there forever. Oddly, I've seen times where it does not. It seems to be very random. I want it to wait 5 seconds no matter what. If it can't connect, it returns error, and my program can move on.


    With the above code I have it where it fails each time now, so I am getting somewhere... My entire code is this:

    Code:
        bool SocketClient::Connect()
        {
        	#ifdef WIN32
            WSADATA  wsaData;
            if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
                fprintf(stderr, "WSAStartup failed.\n");
                exit(1);
            }	
        	#endif
        	
        
        
            sockfd = socket(PF_INET, SOCK_STREAM, 0);
        
            if ((he=gethostbyname(ip.c_str())) == NULL) {  // get the host info 
        		status=2;
                return false;
            }	
        	
            dest_addr.sin_family = AF_INET;          // host byte order
            dest_addr.sin_port = htons(port);   // short, network byte order
        	dest_addr.sin_addr = *((struct in_addr *)he->h_addr);
            memset(dest_addr.sin_zero, '\0', sizeof dest_addr.sin_zero);
        
    	
    		//set non blocking mode:
    		int flags = fcntl(sockfd,F_GETFL,0);
    		fcntl(sockfd,F_SETFL, flags | O_NONBLOCK);
        	
    		//connect:
            int res = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof dest_addr);	
        		if(res==-1)
        		{
        		status=2;
        		return false;
        		}
    			
    		#ifdef WIN32
    		//enable non blocking sockets for win32:
    		u_long arg = 1;
    		ioctlsocket(sockfd, FIONBIO, &arg);	
    		#endif			
        
        	status=1;
        		
            return true;
        }
    http://www.uovalor.com :: Free UO Server

  2. #2
    Join Date
    Jul 2007
    Posts
    609

    Re: Non blocking connect()

    I think I managed to get it working in Linux, not to figure how to get it working in windows. Wish they'd just standardize all these functions so it works cross platform accross the board.



    Code:
    bool SocketClient::Connect()
        {
        	#ifdef WIN32
            WSADATA  wsaData;
            if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) 
    		{
                status=2;
    			return false;
            }	
        	#endif
        	
        
        
            sockfd = socket(PF_INET, SOCK_STREAM, 0);
        
            if ((he=gethostbyname(ip.c_str())) == NULL) {  // get the host info 
        		status=2;
                return false;
            }	
        	
     
    		
    		#ifndef WIN32
    			//declare some temp vars:
    			fd_set myset; 
    			struct timeval tv; 
    			socklen_t lon; 		
    			
    			
    			// Set non-blocking:					
    			int valopt;
    			long arg = fcntl(sockfd, F_GETFL, NULL); 
    			arg |= O_NONBLOCK; 
    			fcntl(sockfd, F_SETFL, arg); 
    		#endif
    		
    		// Try to connect:
    		
    		dest_addr.sin_family = AF_INET;          // host byte order
    		dest_addr.sin_port = htons(port);   // short, network byte order
    		dest_addr.sin_addr = *((struct in_addr *)he->h_addr);
    		memset(dest_addr.sin_zero, '\0', sizeof dest_addr.sin_zero);
    		int res = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); 
    
    		#ifndef WIN32
    			if (res < 0) { 
    			 if (errno == EINPROGRESS) { 
    				tv.tv_sec = m_contimeoutsec;
    				tv.tv_usec = m_contimeoutusec; 
    				FD_ZERO(&myset); 
    				FD_SET(sockfd, &myset); 
    				if (select(sockfd+1, NULL, &myset, NULL, &tv) > 0) { 
    				   lon = sizeof(int); 
    				   getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon); 
    				   if (valopt) 
    				   { 
    					  status=2;
    					  return false;
    				   } 
    				} 
    				else { 
    					  status=2;
    					  return false;
    				} 
    			 } 
    			 else { 
    					  status=2;
    					  return false;
    			 } 
    			}
    			
    			
    			// Set to blocking mode again:
    			arg = fcntl(sockfd, F_GETFL, NULL); 
    			arg &= (~O_NONBLOCK); 
    			fcntl(sockfd, F_SETFL, arg); 
    			
    		#else
    			if(res==-1) //TODO: Find a way to setup non blocking sockets in win32 so it does not try to connect forever
    			{
    				status=2;
    				return false;
    			}
    		#endif
    		
        
        	status=1;
        		
            return true;
        }
    http://www.uovalor.com :: Free UO Server

  3. #3
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Non blocking connect()

    I think Windows return WSAEWOULDBLOCK on a non-blocking socket.
    And you might want to use setsockopt to set the socket to nonblocking, that looks more intuitive to me.

    BTW, connect does not try forever. The 'normal' timeout would be about 20 seconds, but I have seen longer times, but definitely not forever.


    HTH,
    Richard

  4. #4
    Join Date
    Oct 1999
    Location
    ks
    Posts
    524

    Re: Non blocking connect()

    dont know if this helps - i have been using CAsyncSocket as both a client and a server to get into sockets. i stubbed my toe trying to connect and WSAEWOULDBLOCK was returned indicating an attempt to a non-blocking socket failed because there was no immediate connection.

    i use the following code to continue to attempt to connect and it works now. strangely (in my mind) the second attempt would also fail because now the
    socket complains that the sonnection already exists.

    i use the following code to set up a series of attempts to connect and have not had a failure yet the basic idea is to keep tyring to connect and get the last error if the return form the connect attempt is 0 BUT determine the connection has been made if the GetLasError() fn sas the conneciton exists:

    Code:
    		
    ErrorCode = SocketToSend.Create();  // no parms because it is a client
    if (ErrorCode == 0){
    	MessageBox(
    		_T("Faliure on SocketToSend.Create()"),
    		Mode,
    		MB_OK
    	);
    }
    else{
    	// use it to listen
    	bool FinallyGotAConnection = FALSE;
    	bool StopThis = FALSE;
    	int i = 0;
    
    	while (StopThis == FALSE){
    		ErrorCode = SocketToSend.Connect(LPCTSTR(Server),Port);
    		if (ErrorCode != 0){
    			FinallyGotAConnection = TRUE;
    			StopThis = TRUE;
    		}
    		else{
    			LastError = GetLastError();
    			if (LastError == WSAEISCONN){
    				FinallyGotAConnection = TRUE;
    				StopThis = TRUE;
    			}
    		}
    
    		i++;
    		if (i > 100){
    			StopThis = TRUE;
    		}
    	}
    	
    	if (FinallyGotAConnection == FALSE){
    		s = GetErrorText(_T("connect"));
    		MessageBox(
    			_T("SocketToSend.Connect(LPCTSTR(Server),Port) fail - error ") + s,
    			Mode,
    			MB_OK
    		);
    	}
    	else{
    		MessageBox(
    			_T("SocketToSend.Connect(LPCTSTR(Server),Port) completed"),
    			Mode,
    			MB_OK
    		);
    	}
    }

  5. #5
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Non blocking connect()

    jim, you did not understand what I tried to explain. As Red Squirrel and you expirienced, calling connect on a non-blocking socket will lead to an error. This is per definition, as a real connection might take some seconds. The error code connect() returns simply indicates this. Under the hood the TCP stack still performs its task to try and establish the desired connection.
    Now, to get an indication when the connection really is available, you could use select() on the low level API or wait for the OnConnect() event on the CAsyncSocket API. Both ways are equivalent because the CAsyncSocket makes use of the lower level Windows/BSD socket API.

    The approach Red Squirrel took is correct, except that he/she uses the wrong error code on Windows.

    HTH,
    Richard

  6. #6
    Join Date
    Oct 1999
    Location
    ks
    Posts
    524

    Re: Non blocking connect()

    how does one wait for the onconnect event?

  7. #7
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Non blocking connect()

    Assuming you are using CAsyncSocket as you stated in that other thread of yours, derive your class from CAsyncSocket and overwrite the virtual OnConnect() method. You might want to read the docs on MSDN on this topic (http://msdn.microsoft.com/en-us/libr...5f(VS.80).aspx)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured