Thread: Could someone explain how to use the Select function.

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    76

    Could someone explain how to use the Select function.

    I have done alot of stuff with Winsock, but it's all with sockets that can olni process one at a time.


    Can anyone tell me how to make a non-blocking socket? [send and recive]

  2. #2
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    LMGTFY

    Depends on OS, really. For most OS, I believe this is it:
    Code:
    int flags = fcntl(socket_fd, F_GETFL);
    fcntl(socket_fd, F_SETFL, flags (add or remove O_NONBLOCK));
    If you happen to be on Windows, it does it differently:
    Code:
    unsigned long what = (0 for blocking, anything else for non-blocking.);
    ioctlsocket(your_socket, FIONBIO, &what);
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by azjherben View Post
    I have done alot of stuff with Winsock, but it's all with sockets that can olni process one at a time.


    Can anyone tell me how to make a non-blocking socket? [send and recive]
    You use BLOCKING sockets with select(), not non-blocking. The purpose of select is to be able to wait until any one of an entire SET of sockets becomes ready for reading instead of blocking on a single one of them.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User
    Join Date
    Mar 2009
    Posts
    76
    This is one of mi header files.
    Tell me if I did it right.


    Code:
    //Socket.cpp
    #include "Socket.h"
    
    Socket::Socket()
    {
        if( WSAStartup( MAKEWORD(2, 2), &wsaData ) != NO_ERROR )
        {
            cerr<<"Socket Initialization: Error with WSAStartup\n";
            system("pause");
            WSACleanup();
            exit(10);
        }
    
        //Create a socket
        
        
        mySocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    
    unsigned long what = (4);
    ioctlsocket(mySocket, FIONBIO, &what);
    
    
        if ( mySocket == INVALID_SOCKET )
        {
            cerr<<"Socket Initialization: Error creating socket"<<endl;
            system("pause");
            WSACleanup();
            exit(11);
        }
    
        myBackup = mySocket;
    }
    
    Socket::~Socket()
    {
        WSACleanup();
    }
    
    bool Socket::SendData( char *buffer )
    {
        send( mySocket, buffer, strlen( buffer ), 0 );
        return true;
    }
    
    bool Socket::RecvData( char *buffer, int size )
    {
        int i = recv( mySocket, buffer, size, 0 );
        buffer[i] = '\0';
        return true;
    }
    
    void Socket::CloseConnection()
    {
        //cout<<"CLOSE CONNECTION"<<endl;
        closesocket( mySocket );
        mySocket = myBackup;
    }
    
    void Socket::GetAndSendMessage()
    {
        char message[STRLEN];
        cin.ignore();//without this, it gets the return char from the last cin and ignores the following one!
        cout<<"Send > ";
        cin.get( message, STRLEN );
        SendData( message );
    }
    
    void ServerSocket::StartHosting( int port )
    {
         Bind( port );
         Listen();
    }
    
    void ServerSocket::Listen()
    {
        //cout<<"LISTEN FOR CLIENT..."<<endl;
        
        if ( listen ( mySocket, 1 ) == SOCKET_ERROR )
        {
            cerr<<"ServerSocket: Error listening on socket\n";
            system("pause");
            WSACleanup();
            exit(15);
        }
        
        //cout<<"ACCEPT CONNECTION..."<<endl;
        
        acceptSocket = accept( myBackup, NULL, NULL );
        while ( acceptSocket == SOCKET_ERROR )
        {
            acceptSocket = accept( myBackup, NULL, NULL );
        }
        mySocket = acceptSocket;
    }
    
    void ServerSocket::Bind( int port )
    {
        myAddress.sin_family = AF_INET;
        myAddress.sin_addr.s_addr = inet_addr( "0.0.0.0" );
        myAddress.sin_port = htons( port );
        
        //cout<<"BIND TO PORT "<<port<<endl;
    
        if ( bind ( mySocket, (SOCKADDR*) &myAddress, sizeof( myAddress) ) == SOCKET_ERROR )
        {
            cerr<<"ServerSocket: Failed to connect\n";
            system("pause");
            WSACleanup();
            exit(14);
        }
    }
    
    void ClientSocket::ConnectToServer( const char *ipAddress, int port )
    {
        myAddress.sin_family = AF_INET;
        myAddress.sin_addr.s_addr = inet_addr( ipAddress );
        myAddress.sin_port = htons( port );
        
        //cout<<"CONNECTED"<<endl;
    
        if ( connect( mySocket, (SOCKADDR*) &myAddress, sizeof( myAddress ) ) == SOCKET_ERROR )
        {
            cerr<<"ClientSocket: Failed to connect\n";
            system("pause");
            WSACleanup();
            exit(13);
        } 
    }

  5. #5
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Quote Originally Posted by brewbuck View Post
    You use BLOCKING sockets with select(), not non-blocking. The purpose of select is to be able to wait until any one of an entire SET of sockets becomes ready for reading instead of blocking on a single one of them.
    Generally, you use non-blocking sockets. Using blocking sockets would provide a disadvantage that you would only be able to perform 1 recv() until you would have to return to a select() call. If more data is available then your initial recv() on the socket, then you'll miss out until you call select() again. If you use non-blocking sockets, however, then you can just recv() until there is no more data.

    Furthermore, and more seriously, the man page for select() notes that:
    Quote Originally Posted by man 2 select
    Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.
    As for the OP's code, some notes:
    1) You can use INADDR_ANY in place of inet_addr( "0.0.0.0" );
    2) If WSAStartup() fails, WSACleanup() is probably unneeded.
    3)
    Code:
        acceptSocket = accept( myBackup, NULL, NULL );
        while ( acceptSocket == SOCKET_ERROR )
        {
            acceptSocket = accept( myBackup, NULL, NULL );
        }
        mySocket = acceptSocket;
    do-while?
    4) '4' is an arbitrary number... just because the man page said 'non-zero' doesn't mean you have to follow it that closely. Try something more sane, like... 1? Otherwise, readers are going to be wondering what '4' does.
    5) In SendData(), check the return value. send() might not send() everything you ask of it, especially with non-blocking sockets.
    5) RecvData has a buffer overflow.
    Code:
    bool Socket::RecvData( char *buffer, int size )
    {
        int i = recv( mySocket, buffer, size, 0 );
        buffer[i] = '\0';
        return true;
    }
    First, check that return value. If something goes wrong (ie, error, or since it's a non-blocking socket, it signals that it would block) then it will return negative, and you'll have buffer[negative #], which is obviously not a Good Thing™. Furthermore, in the case of extreme success, recv() actually recv's size bytes, it'll return size, and buffer[size] is off by one. (If it's string data though, you do need to terminate that buffer though! recv() size-1, and make sure that recv()'s ret isn't negative!)
    Last edited by Cactus_Hugger; 07-03-2009 at 12:56 PM.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Troubleshooting Input Function
    By SiliconHobo in forum C Programming
    Replies: 14
    Last Post: 12-05-2007, 07:18 AM
  2. Calling a Thread with a Function Pointer.
    By ScrollMaster in forum Windows Programming
    Replies: 6
    Last Post: 06-10-2006, 08:56 AM
  3. Bisection Method function value at root incorrect
    By mr_glass in forum C Programming
    Replies: 3
    Last Post: 11-10-2005, 09:10 AM
  4. Change this program so it uses function??
    By stormfront in forum C Programming
    Replies: 8
    Last Post: 11-01-2005, 08:55 AM
  5. Replies: 5
    Last Post: 02-08-2003, 07:42 PM