in reply to Re^3: Trying to thread a daemon with threads and Thread::Queue
in thread Trying to thread a daemon with threads and Thread::Queue

Recoup on:
Re^6: Trying to thread a daemon with threads and Thread::Queue

The following part of the code (in the handleConnection() sub) has a serious flaw:
shutdown $socket, 2;
From: perldoc on shutdown()
"It's also a more insistent form of close because it also disables the file descriptor in any forked copies in other processes."

The thread tries to force closing the socket using shutdown() (after the thread is done with the connection) while the main accept thread still has it open, causing the script to abnormally terminate without any errors messages.
Removing this line from the handleConnection() sub and keeping only "close socket;", re-running the script, then simulating a client connection and request returns the expected data, but the client sees the connection still open (because the socket wasn't closed from server)

This is due to the construct of the main accept thread:
while ( my ($new_sock, $clientAddr) = $sock->accept() ) { my ( $clientPort, $clientIp ) = sockaddr_in( $clientAddr ); # put the connection on the queue for a reader thread my $fno = fileno($new_sock); $sockets{ $fno } = $new_sock; $Q->enqueue( "$fno\0$clientIp" ); while ( $Qclean->pending ) { my $fileno = $Qclean->dequeue(); $log->warning("Attempting to close handle associated with file +no: $fileno"); close $sockets{ $fileno }; delete $sockets{ $fileno }; } }
Basically the while ( $Qclean->pending ) is not immediately triggerd (to close the socket in the main accept thread) because it is inside the while ( ... $sock->accept() ), and won't happen until another client connects, so the first client will just hang because it sees the socket on the server is still open.

In other words, client-A connects and sends request, gets response, but the server doesn't close the socket, so the client stays connected even though the server is done sending.
Then when client-B connects, Qclean is checked and sees the socket associated with client-A needs to be closed, so it goes ahead and closes it.

I'm stumped... Any thoughts/ideas on how to fix this?

Update:
I tried adding this early in my script:
SIG{PIPE}='IGNORE';
After re-adding the shutdown() line before close() in the handleConnection() sub to avoid the script blowing up because of SIGPIPE:
shutdown $socket, 2; close $socket;
But then the client doesn't get the response (what is written on the socket by the server thread from the handleConnection() sub), just a connection drop :S

Replies are listed 'Best First'.
Re^5: Trying to thread a daemon with threads and Thread::Queue
by BrowserUk (Patriarch) on Aug 29, 2008 at 15:07 UTC
    The thread tries to force closing the socket using shutdown() (after the thread is done with the connection) while the main accept thread still has it open, causing the script to abnormally terminate without any errors messages.

    Hmm. Have you managed to track down what code is executing when that silent abnormal termination occurs?

    In my tests (under win32), if I dont use shutdown in the hendler thread, the client connection stays open until the main thread gets around to closing its copy of the socket. Which doesn't sound so bad until you realise that the main thread will never get around to closing the socket until it receives a new incoming connect to terminate the accept.

    So, you get a burst of incoming connects, queue up the file numbers and store the sockets in the main thread until the main threads timeslice ends. Then the child threads get a lookin, and process the requests, and close their copies of the handles.

    But, until the main thread both gets a timeslice, and receives new connect request all the clients your child threads processed are sitting there with open connections. As the main thread will be able to queue up (potentially) several hundred connections before it relinguishes its timeslice, and your child threads will process and close but not disconnect those same several hundred once they get timeslices, there is the potential for having several hundred clients hanging around waiting for a new client to connect before their connections will be terminated. If your traffic is in any way 'bursty', that could prove to be a big problem.

    If the abend is down to the main thread trying to close a socket that has already been closed--though I wouldn't have though that likely; There is not logic to the idea that shutdown would cause this failure, as this use is exactly what it is designed for--then it would be better to do the shutdown in the handler threads and just discard the sockets in the main thread rather than attempting to close them.

    Needless to say, but I will anyway :) I cannot reproduce your failure here, so you are going to have to explore the reason for the abend yourself.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.