Question

For a class project, we are instructed to create simple programs using Winsock2. I created a beginning echo program, and now I am attempting to implement a way for the program to find the host itself within a room. The room is on a private network, 192.168.xxx.xxx, the subnets go up by 10, and the computers that can be running the server are numbers 50, 51, and 52 on each subnet. A simple implementation I was planning on doing was to just attempt to connect to each computer, if it can, it is the server. Not the best solution, but it still uses Winsock2 and it works for me.

SOCKET connectsock(const char *host, const char *service, const char *transport )
{
struct hostent  *phe;   /* pointer to host information entry    */
struct servent  *pse;   /* pointer to service information entry */
struct protoent *ppe;   /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address     */
int s, type;    /* socket descriptor and socket type    */

while (1)
{
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;

    /* Map service name to port number */
    if ( pse = getservbyname(service, transport) )
        sin.sin_port = pse->s_port;
    else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 )
        errexit("can't get \"%s\" service entry\n", service);

    /* Map host name to IP address, allowing for dotted decimal */
    if ( phe = gethostbyname(host) )
        memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
    else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
        errexit("can't get \"%s\" host entry\n", host);

    /* Map protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
        errexit("can't get \"%s\" protocol entry\n", transport);
    /* Use protocol to choose a socket type */
    if (strcmp(transport, "udp") == 0)
        type = SOCK_DGRAM;
    else
        type = SOCK_STREAM;

    /* Allocate a socket */
    s = socket(PF_INET, type, ppe->p_proto);
    if (s == INVALID_SOCKET)
        errexit("can't create socket: %d\n", GetLastError());

    /* Connect the socket */

    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("can't connect to %s.%s: %d\n", host, service, GetLastError());
        host = "localhost";
    }
    else
        break;
}
return s;

}

This loop works fine, and simply connects to the first IP address, 192.168.10.50, and then if it pulls an error, connects to the next host, if another error, it tries a third host, so on and so forth until it connects successfully. Since I am still only testing the program, I just have it redirect to connecting to the localhost after the first failure.

It works perfectly fine as is, the only problem is within the class, there is no latency. Therefore the connections, if available, happen a tenth of a second. By default, the program will try to connect to the first computer, and will not be able to, but it sits and waits 5 seconds for a response before switching to the next host.

Since it is a small scale program within a closed internet, I should have no problem shortening the wait period to half a second, but my question is how?

Is it possible, and if not, what can I do to correct it? Is there a more efficient way to make a host find a server that can move? The server will change computers.

Was it helpful?

Solution

You should be able to do this scanning effectively with a single thread if you employ non-blocking sockets. In order to accomplish this, you would use the ioctlsocket() function.

You can roll this into your connectsock() function fairly easily. If you slip this block of code between your socket() and connect() calls, it should do the trick.

static u_long iMode=1; 
ioctlsocket(s,FIONBIO,&iMode);

This will make all the sockets created by connectsock() become non-blocking. What this means is that all operations on these sockets will return immediately, regardless of whether or not there is data waiting to be read or written.

You can fire off as many connectsock() calls as you need, and just track all the sockets that are getting created in an array. If you try to read or write to the sockets immediately, the attempts will likely fail. If you wait a few milliseconds though, the socket will likely be established and attempts will succeed. You can then run them through any winsock function that can return an error code, and if the error code is anything other than SOCKET_ERROR, then that should mean there's a client on the other side of the socket.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top