Advertisement

Server accepts just one connection

Started by May 30, 2006 03:06 PM
1 comment, last by rogierpennink 18 years, 8 months ago
Hey, I've tried asking about it in the beginner's section, but then I realised I was both on the wrong forum and asking the wrong question so I'll try again here... ;) I'm writing a MUD server, with a win32 GUI. As I'm not much into multithreading yet I have put the networking and the updating of the GUI in the same thread. However, as it is, the server only accepts one question and then (seems to) stop(s) listening... At least, the FD_ACCEPT event doesn't get fired any more... I'll shortly explain the structure of my project and some code below.. Basically, the server (as it is) consists of four files, one main.cpp initializes the GUI and loads the header files (Defines.h, Sockets.h, Functions.h) In sockets.h I declare a few globals: // Global serversocket variables SOCKET serversocket; CLIENT client[MAX_CLIENTS]; WSADATA WsaData; sockaddr_in localAddress; I know I my serversocket and localaddress shouldn't be global, but meh... I want to get it to work above all. When the Start Server button is pressed, the StartServer() function gets called, which calls InitServer() and puts the results in an editbox. Below is the initserver function:

int InitServer ( SOCKET serversocket, WSADATA WsaData, sockaddr_in localAddress, int port, HWND hWnd ) {

// Most of the arguments passed are globals... 

    // Start up winsock (and fill the WsaData struct)
    int WSAreturn = WSAStartup( 0x101, &WsaData );

    if( WSAreturn != 0 ) {
        return ERROR_NOWINSOCK;
    }

    // Now we populate the sockaddr_in structure
    localAddress.sin_family = AF_INET;                         //Address family
    localAddress.sin_addr.s_addr = INADDR_ANY;                 //Wild card IP address
    localAddress.sin_port = htons( port );                     //port to use

    // Create our socket
    serversocket = socket ( AF_INET, SOCK_STREAM, 0 );

    if ( serversocket == INVALID_SOCKET ) {
	closesocket ( serversocket );
	WSACleanup();
	return INVALID_SOCKET;
    }	

    if ( WSAAsyncSelect ( serversocket, hWnd, SM_SOCKETEVENT, FD_ACCEPT|FD_CONNECT|FD_CLOSE|FD_READ|FD_WRITE ) == SOCKET_ERROR ) {
	closesocket ( serversocket );
	WSACleanup();
	return ERROR_MESSAGEROUTER;
    }

    // Bind our socket...
    if ( bind ( serversocket, (sockaddr*) &localAddress, sizeof( sockaddr ) ) == SOCKET_ERROR ) {
	closesocket ( serversocket );
	WSACleanup();
	return ERROR_NOBIND;
    }

    // Attempt to listen on given port
    if ( listen( serversocket, SOMAXCONN ) == SOCKET_ERROR ) {
	closesocket ( serversocket );
	WSACleanup();
	return ERROR_NOLISTEN;
    }

    unsigned long b = 1;
    ioctlsocket ( serversocket, FIONBIO, &b );

    return 1;
}

As you can see, i set up a listening socket (serversocket) and I wait in the Window Procedure for the FD_ACCEPT message, which comes as the wParam of my self-created SM_SOCKETEVENT message. Underneath code shows the action that gets taken on this event:

case SM_SOCKETEVENT:
{

    int event = WSAGETSELECTEVENT(lParam);
    HWND hOutput = GetDlgItem ( hWnd, TXT_OUTPUT );	
		
    if ( event == FD_ACCEPT ) {

	UpdateOutput ( hOutput, (char *) " - A client is connecting." );

	SOCKADDR_IN * clientAddress;
	int clientlen = sizeof ( clientAddress );
	SOCKET clientsocket;
			
	while ( clientsocket == INVALID_SOCKET) {
	    clientsocket = accept ( serversocket, &clientAddress, &clientlen );
	}

	if ( clientsocket == INVALID_SOCKET ) {

	    char * tError = (char *) malloc ( 20 * sizeof(char) );
	    sprintf ( tError, "Error: %u", WSAGetLastError() );
	    UpdateOutput ( hOutput, tError );

	} else {

            UpdateOutput ( hOutput, "[server]: Connection established" );

	}	
			

    }

    return 0;

    break;
}

As you can see, it simply accepts the connection and then does nothing with it obviously because I want it to work before I do anything with the clientsocket. What's wrong with this (apart from the globals)? Well, I can't accept more than one connection. I thought listen() would put serversocket in a continuous listening state, but after accepting only one connection, the FD_ACCEPT event never gets fired again... What should I fix?
	SOCKET clientsocket;				while ( clientsocket == INVALID_SOCKET) {


This will likely never go into the while() loop, as "clientsocket" will have an undefined value the first time through. If you turn on all compiler warnings, the compiler will likely warn you about this, too -- it's always a good idea to turn on all warnings, and change the code to not emit those warnings.

Also, clientsocket cannot possibly be INVALID_SOCKET after that while loop -- because then you'd be spinning in the while loop. Instead, as it is, you will just fall through your code and pretend you had a good socket, when really you have random stack junk.


In the server code, you only want to select on FD_ACCEPT for the listening socket, and you want to do that after you've called listen().

enum Bool { True, False, FileNotFound };
Advertisement
You are... my hero.

Sometimes I am amazed by my lack of insight and/or logical thinking. I'll up your rating ;)

This topic is closed to new replies.

Advertisement