Thread: WaitForMultipleObjects and listen()/accept()

  1. #1
    Registered User
    Join Date
    May 2004
    Posts
    73

    WaitForMultipleObjects and listen()/accept()

    Hey everyone, I'm having some trouble using WaitForMultipleObjects to wait for incoming connections (which I would later accept()).

    My code simply uses one thread to start listening, and then uses the main thread to try to connect to it.

    Code:
    // Main Thread
    int main() {
    	WSAData wsaData;
    	if (WSAStartup(MAKEWORD(1, 1), &wsaData))
    		assert(false);
    
    	pthread_t mynewthread;
    	pthread_create(&mynewthread, NULL, threadMain, NULL);
    
    	// Wait for the listener thread to be ready
    	Sleep(2000);
    
    
    	// Now try to connect to the thread via tcp
    
    	SOCKET socket = ::socket(AF_INET, SOCK_STREAM, 0);
    
    	struct hostent *hp = gethostbyname("127.0.0.1");
    	assert(hp);
    
    	struct sockaddr_in server;
    	server.sin_family = AF_INET;
    	memcpy(&server.sin_addr.s_addr, hp->h_addr, hp->h_length);
    	server.sin_port = htons(1337);
    
    	if (::connect(socket, (const sockaddr *)&server, sizeof(server))) {
    		std::cout << GetLastErrorMessage(GetLastError()) << std::endl;
    		assert(false);
    	}
    
    	cout << "connected successfully!" << endl;
    }
    Code:
    // Listener Thread
    
    
    HANDLE getEventAndEnableNonblockingMode(SOCKET socket) {
    	HANDLE socketEventHandle = WSACreateEvent();
    	WSAEventSelect(socket, socketEventHandle, FD_ACCEPT | FD_READ | FD_CLOSE);
    	return socketEventHandle;
    }
    
    void closeEventAndDisableNonblockingMode(SOCKET socket, HANDLE socketEventHandle) {
    	// We need to close it here because having an event
    	// open puts the socket in non-blocking mode. we need it to be in blocking mode for
    	// things like accept().
    	WSACloseEvent(socketEventHandle);
    	WSAEventSelect(socket, NULL, 0);
    
    	// Now we make it blocking.
    	unsigned long resultBuffer = 0;
    	unsigned long resultBufferBytesWritten = 0;
    	unsigned long newNonblockingEnabled = 0;
    	int error = WSAIoctl(socket, FIONBIO, &newNonblockingEnabled, sizeof(unsigned long), &resultBuffer, sizeof(resultBuffer), &resultBufferBytesWritten, NULL, NULL);
    	assert(error == 0);
    }
    
    void *threadMain(void *args) {
    	SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
    	assert(listenSocket >= 0);
    
    	struct sockaddr_in name;
    	name.sin_family = AF_INET;
    	name.sin_addr.s_addr = htonl(INADDR_ANY);
    	name.sin_port = htons(1337);
    	int nameStructLength = sizeof(name);
    
    	if (bind(listenSocket, (struct sockaddr *)&name, nameStructLength)) {
    		int error = GetLastError();
    		std::cout << "Error in connection listener: " << GetLastErrorMessage(error) << std::endl;
    	}
    
    	HANDLE socketEventHandle = getEventAndEnableNonblockingMode(listenSocket);
    	HANDLE events[1] = { socketEventHandle };
    
    	DWORD result = WaitForMultipleObjects(1, events, false, INFINITE);
    
    	closeEventAndDisableNonblockingMode(listenSocket, socketEventHandle);
    
    	if (result == WAIT_OBJECT_0) {
    
    	}
    	else {
    		assert(false);
    	}
    
    	cout << "wfmo returned!" << endl;
    
    	return NULL;
    }
    Any idea why WaitForMultipleObjects isnt waiting for connections like listen() would?

    Thanks!

    PS. I need to use WaitForMultipleObjects because soon I will be waiting on more than just the socket, I'll need to respond to a number of other events as well.
    Last edited by Verdagon; 12-15-2011 at 01:17 AM.

  2. #2
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    You haven't called listen() anywhere. The event setting and all that might be magic, but it's no mind reader

    Code:
    WSACloseEvent(socketEventHandle);
    WSAEventSelect(socket, NULL, 0);
    These want to be the other way around or you run the risk of someone else creating an event with the same handle value, and it being set by one of socket's notifications before you get to revoking them.

    Code:
    GetLastError();
    All of these which repond to a socket related error want to be WSAGetLastError()

    Code:
    WSAStartup(MAKEWORD(1, 1), &wsaData);
    Unless you're going to be running on Win 9x this always wants to be (2, 2). 1.x switches some internal things to slower versions used by those old implementations.

    Last thing in case this just isn't testing code:
    Code:
    Sleep(2000);
    Sleeping is a bad way to ensure another thread has initialized things far enough, since you never know what the OS scheduler is doing. Consider passing in an event handle and setting it when setup has completed.

  3. #3
    Registered User
    Join Date
    May 2004
    Posts
    73
    Thanks for the reply! Indeed the Sleep was just for testing, and thanks for the tips on WSAStartup and the order of closing the event.

    The original plan was to use listen() and accept() after the WaitForMultipleObjects call. I would just use listen() but it blocks unless there's a connection waiting. I need to use WaitForMultipleObjects to until there's a connection waiting, then listen(), then accept(). The reason I need WFMO is because I need to be able to add a custom event to it, so I can interrupt its waiting.

    Is there a way to enable some sort of listening mode or something, before I do WaitForMultipleObjects?

    Thanks a bunch!

  4. #4
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    I would just use listen() but it blocks unless there's a connection waiting
    When your listen socket is non-blocking it doesn't, neither does accept.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    What a bizarre mixture of POSIX and Windows... pthreads? Yet you're using the Windows-specific WFMO call? Why?

    Anyway, you could run the socket accept loop in another thread, and signal to your main loop through an event object (see CreateEvent() call) which is signaled by the socket loop. That way you still have one place where you WFMO on everything. Leave the Windows specific crud out of the networking stuff.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. WaitForMultipleObjects for Boost.Thread?
    By Elysia in forum C++ Programming
    Replies: 8
    Last Post: 05-23-2009, 12:18 PM
  2. help with listen and sockets.
    By Ironic in forum Networking/Device Communication
    Replies: 1
    Last Post: 04-05-2009, 02:41 AM
  3. What exactly does listen() do from winsock 1.1
    By *DEAD* in forum Networking/Device Communication
    Replies: 6
    Last Post: 12-14-2007, 06:48 PM
  4. the listen() function
    By Da-Nuka in forum Networking/Device Communication
    Replies: 9
    Last Post: 03-07-2005, 02:44 PM
  5. What do you listen to?
    By FloatingPoint in forum A Brief History of Cprogramming.com
    Replies: 35
    Last Post: 06-24-2003, 09:41 PM