tags:

views:

927

answers:

7

I am experimenting with C++ winsockets. I want to create a method with which I can find the server on the network, without knowing it's IP. To do this I simply loop my connect method through IP adresses 192.168.1.0 to 192.168.1.255. However, the time between each connect is quite large, the program tends to wait at the: connect(nBytes, (sockaddr*)&server, sizeof(server)) statement for at least 30 seconds if not longer. My questions are the following: Why is this happening, how can I solve this and might there be an entirely different, better way to find the server?

my connect method:

SOCKET connect(char *ipAdress)
{
WSAData wsaData;

if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR)
    return errorReport("Could not create startup struct");

nBytes = socket(AF_INET, SOCK_STREAM, 0);

if (nBytes == SOCKET_ERROR)
    return errorReport("Socket could not be created");

struct hostent *host_entry;

if ((host_entry = gethostbyname(ipAdress)) == NULL)
    return errorReport("Cannot find server.");

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(1337);
server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;

if (connect(nBytes, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
    WSACleanup();
    return errorReport("Failed to connect to server.");
}

if (nBytes == -1)
{
    WSACleanup();
    disconnect(nBytes); 
    return errorReport("Could not connect");
}

return 0;
}

Also, feel free to tell me anything I'm doing wrong in the current connect method.

+3  A: 

The long delay is caused by the socket's need to time out before returning to the caller. To reduce the total execution time, you should make multiple worker threads that simultaneously connect to separate IP-addresses.

Dr. Sbaitso
+1  A: 

I would do a research to find out if winsock supports asynchronous I/O.

Anonymous
+2  A: 

OK, a couple things here.

First, connect is designed to wait for a bit before timing out in case the server is busy. You can adjust the timeout length, although I can't remember exactly how to do that off the top of my head.

Second, your code will find a server, but how do you know it's the server you are looking for? It could be some other app that is just listening on the same port. Unless you are just doing a scan for any server in particular, you'll need to do some verification to be sure of who you are talking to on the other end.

Finally, assuming you are writing both the client and the server, a better solution would be to have the client send out a broadcast/multicast message and have the server (or servers if there are more than one) listen for and respond to that message. The client then just waits some specified period of time for responses to figure out where the server(s) are.

Eric Petroelje
+1  A: 

Is the server IP address so random that you need to do this each time? I have not done any socket programming in a long time, but with timeouts and such this might not get much better.

Other options:

  • How about a configuration file on a network share with the IP address? This could be rewritten whenever the server starts up.
  • make the server's IP address static and hard-code or put in a configuration file
  • Look-up via DNS or NETBIOS name of the machine
crashmstr
A: 

If you know the server is on the Subnet, why not send a broadcast message with the local reception port number as the message data? Then the server can simply listen for this message and connect back to that port, or send it's own config data back to that port so the client can connect directly. In this way, you only need to send one message out instead of looping over 256 IP addresses.

Furious Coder
A: 

I've done this in the past with great success back in the "everybody has port 139" open days.

I found that using multiple threads (Sadly, I used about 500, but it was a one time shot and just for fun) and I pinged the server before I attempted a connection allowed me to traverse through several thourand IP's per second.

I still have the source code (C++) if you would like to check it out just leave me a message.

Also, why on earth would it ever be necessary to scan IPs? Even if its dynamic, you should be able to look ip up by its host name. See gethostbyname() or getaddrinfo().

NTDLS
Sure, would love to check it out! Thanks!
I've downloaded it, will take a look at it soon, thanks again!
A: 

I see you are using windows. But if you are using Linux you can create a connection function which has a timeout by combining non-blocking sockets and select:

int connect_with_timeout(int sock, struct sockaddr *addr, int size_addr, int timeout) {
#if defined(Linux)
    int    error = 0;
    fd_set   rset;
    fd_set   wset;
    int    n;

    // set the socket as nonblocking IO
    int flags = fcntl (sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    errno = 0;

    // we connect, but it will return soon
    n = connect(sock, addr, size_addr);

    if(n < 0) { 
     if (errno != EINPROGRESS) {
      return -1;
     }
    } else if (n == 0) {
     goto done;
    }

    FD_ZERO(&rset);
    FD_ZERO(&wset);
    FD_SET(sock, &rset);
    FD_SET(sock, &wset);

    struct timeval tval;
    tval.tv_sec = timeout;
    tval.tv_usec = 0;

    // We "select()" until connect() returns its result or timeout
    n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0);
    if(n == 0) { 
     errno = ETIMEDOUT;
     return -1;
    }

    if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
     socklen_t len = sizeof(error);
     if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
      return -1;
     }
    } else {
     return -1;
    }

done:
    // We change the socket options back to blocking IO
    if (fcntl(sock, F_SETFL, flags) == -1) {
     return -1;
    }
    return 0;
#else
    return connect(sock, addr, size_addr);
#endif
}
Evan Teran