-
Make accept() stop
Ok, I have a program that creates threads that each listen on a port, The problem is that when I call accept() in the thread, It means I can't close the thread without calling TerminateThread(), which I've been advised in the past not to do. So what I'm asking, is there a way that I can cause accept() to end? I tried calling WSACleanup() from my main thread, but It doesn't effect anything?
I just need a way to cause an error within accept() to make it stop.
thanks
-
what you are looking at is one of the problems of non-blocking sockets. This can easily(and I do mean easily) be resolved if you poll a socket to check to see if there is any incoming data, if so then you can try to use accept(a socket listening for connections should do just that, and not try to listen for other data, IMO).
-
That is one of the problems of blocking sockets. Two options are, port your program to using asynchronous sockets, or do the polling thing that EvBladeRunnervE suggested (look into select()).
-
Just for kicks I wrote an abortable accept function. It is untested so let me know if it works. Error checking could be better.
Code:
/*
* Works like the normal accept(), except that it takes an abort event. When this event is
* signalled this function will return INVALID_SOCKET immediately.
*/
SOCKET AbortableAccept(SOCKET s, struct sockaddr* addr, int* addrlen, HANDLE hEventAbort)
{
SOCKET sockRet;
HANDLE hEvents[2];
ULONG setting[2] = { 0, 0 };
if (hEventAbort == NULL)
{
/* Normal, non-abortable accept(). */
return accept(s, addr, addrlen);
}
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* Will be signalled for an incoming connection. */
hEvents[1] = hEventAbort; /* Will be signalled by another thread to abort the accept operation. */
WSAEventSelect(s, hEvents[0], FD_ACCEPT); /* Puts socket in non-blocking mode and
* tells windows to signal hEvents[0] when the
* accept() has completed or an error occurs. */
if (WaitForMultipleObjects(2, hEvents, FALSE, INFINITE) == WAIT_OBJECT_0)
{
/* An incoming connection has arrived or a network error has occurred. */
sockRet = accept(s, addr, addrlen);
}
else
{
/* Abort event was signalled or WaitForMultipleObjects error. */
sockRet = INVALID_SOCKET;
}
/* Cleanup event signalling */
WSAEventSelect(s, hEvents[0], 0);
CloseHandle(hEvent);
/* Put sockets back into blocking mode */
ioctlsocket(s, FIONBIO, &setting[0]);
ioctlsocket(sockRet, FIONBIO, &setting[1]);
return sockRet;
}
/* Sample usage. */
/* Create a global manual-reset event. */
g_hAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/* Start an abortable accept. */
sock = AbortableAccept(s, (struct sockaddr*) &addr, &addrlen, g_hAbortEvent);
/* In another thread - signal the event and abort the accepts that are using it. */
SetEvent(g_hAbortEvent);
-
So, Hunter2, could you please point me to a link that explains how to convert my program to use asynchronous sockets?
anonytmouse, even though that code looks very interesting, I think it's a little ahead of me at the moment.
-
I'm pretty sure there's some links to tutorials at the top of this forum, most of them will deal with asynchronous Winsock to some extent.
Here's Johnnie's tutorial, it covers the very very basics of using asynchronous winsock at the bottom of the tutorial.. you can probably find more if you search on Google.
http://www.hal-pc.org/~johnnie2/winsock.html
-
Ok, so I got it semi-working. If I only call WSAAsyncSelect() once, it's fine. But if I try to call it again for another socket, it fails. why can this be?
-
I don't think that should happen. Can you post some code?
-
Strange, It's now working because I took out a piece of unrelated code. Is there anyway to get the port back from a socket?
I tried:
Code:
sockaddr_in test;
SOCKET sock = accept((SOCKET)wParam,(sockaddr*)&test,&x);
wsprintf(addstrbuff,""Port:%d ",(int)ntohs(test.sin_port));
MessageBox(0,addstrbuff,"",0);
But the port is completely wrong?
-
What are you getting as the value for the port? At a glance, your code looks correct. Also make sure that x is initialized to sizeof(struct sockaddr) before you pass its address to accept().
-
I usualy get a random number above 3000, If the first random number is 3980 the next will be 3981, and so on, no matter which port it is.
-
Just figured it out, It's giving me the remote port, not local. Is it possible to get the local port at which a connection is established?
-
Typically, for a server socket, the local port is whatever you bound it to. However, if you need a function to retrieve this information, you can use getsockname().
-
Simply closing the socket from another thread will cause accept() to return.
-
random: Johnie2 updated his tutorial? Nice job man. I remember him asking me about why I called it incomplete once. Impressively better.