Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

IO::Socket::INET, threads, and screwy recv() results

by jettero (Monsignor)
on Jan 03, 2006 at 19:28 UTC ( #520702=perlquestion: print w/ replies, xml ) Need Help??
jettero has asked for the wisdom of the Perl Monks concerning the following question:

To be sure, similar questions have been asked before. I found tye's answer to be most helpful -- though it's from a totally different thread.

I have a socket that I wish to use from two threads. It's not a Listen socket. My &listener dies after a while though. This death is reliable, though you can't really say when before hand. If I do the same test without threads it works fine, so I figure I need to dup the IO::Socket. The problem with tye's "<&".fileno($sock) is that it returns an IO::Handle, and I wish to call the connected() from IO::Socket later.

Please help. Here is a small sample of what I'm trying to do:

my $sock = new IO::Socket::INET( PeerAddr => "igs.joyjoy.net", PeerPort => "6969", Proto => "tcp" ); my $sender = new threads( \&sender => $sock ); my $listener = new threads( \&listener => $sock ); $sender->join; $listener->join; exit; sub sender { my $sock = shift; print $sock $_ while <>; } sub listener { my $sock = shift; while( $sock->connected ) { my $msg = ""; my $sock_addr = recv( $sock, $msg, 1024, 0 ); unless( defined $sock_addr ) { die "socket error"; } SHOW: { local $| = 1; print $msg; } } }

I also realize there are modules like Net::Telnet that do a lot of this stuff for you, but I wish to learn how to do this by hand.

UPDATE (several hours later): It doesn't die at all, the recv() quits stuffing data into $msg though. It doesn't return undef either, as it would if there were an error, and it stays connected() because it starts looping really fast through the while(). I guess I have no idea why the code above doesn't work.

UPDATE II (1/5/6): I changed the code above around a little. This code actually does work as an IGS client. However, very occasionally the recv() will begin to get 0 results back and the while() loop starts firing a billion times a second (never to recover). This happens more frequently with a version where I pass fileno() and $newiosocket->fdopen($fileno, "+>") in each thread instead.

Comment on IO::Socket::INET, threads, and screwy recv() results
Select or Download Code
Re: IO::Socket::INET (dup?)
by Anonymous Monk on Jan 04, 2006 at 01:59 UTC
    The problem is that both threads have a copy of $sock, and each one will close() it when they exit. You're trying to dup() the socket to stop that, but why not set $sock as shared?
      That is most definitely not the problem actually. If you look closely, neither thread exits at all. The join() blocks until the threads finish so you have to SIGINT your way past the joins to close the socket.

      Also, you can't my $sock : shared. I tried that. It generates a "stupid type to share" error or something like that.

      Anyway ... Thanks for you input. I actually did try the things you suggested.

      Because you can't share blessed objects between threads.

      C.

Re: IO::Socket::INET (dup?)
by zentara (Archbishop) on Jan 04, 2006 at 12:08 UTC
      I actually linked to that first one at the top...

      I have yet to try a $new_socket->fdopen( $id, "+>" ) though. It's worth a shot. But I think the actual problem relates to the wrong choice of recv(). I'm pretty sure I need to also try read() with atmark() instead.

      Do you have to flush the socket (or something) somehow when you use recv()? Ultimately I need to do a lot more experiments. This project should not be difficult. *sigh*

Re: IO::Socket::INET, threads, and screwy recv() results
by BrowserUk (Pope) on Jan 04, 2006 at 14:02 UTC
    If I do the same test without threads it works fine...

    Really? Could you show me your non-threaded code that allows you to be both server and client talking through the same port and the same IO::Socket::INET handle at the same time?

    Because that is what you are trying to do in the above code.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      No, not really. In my update I admit that I'm having strange results whether I fork() or new threads(). I obviously just don't know how to do what I'm trying to do at all...

      I'm experimenting with the $sock=new IO::Socket; $sock->fdopen() that someone linked to. Perhaps that'll fix me up.

      I think you misread the code. To me it looks like he's trying to read from the socket with one thread, and write with the other.. which sounds perfectly valid (not that Ive a clue why one would need threads for it).

      C.

        Well maybe, but it is very confusing code.

        He makes a client style connect to a remote system and port. He then passes the socket, without having checked whether the connection succeeded to two threads.

        One of those threads labelled 'sender', sits in a tight loop reading from <> (presumably intended to be STDIN) and sends whatever it reads to the remote system. It never checks whether the socket is connected, or if it is still connected.

        The other thread, labelled 'listener' despite that it does use 'listen', sits and attempts to receive anything that arrives on the the port and echo it to STDOUT. This does check whether the port is connected, but just then just falls off the end of the thread. It also just dies if the recv fails. In either case, there is no attempt to coordinate termination with the sender thread, which will just continue to attempt to read and send forever.

        The OP claimed that "If I do the same test without threads it works fine", but with an absence of any calls to listen, connect or accept, and no coordination between reads and writes, it is very difficult to see how that could ever be.

        Essentially, the OP appears to be leaping into threads without making any attempt to understand the basics of socket communications in a non-threaded environment. I had hoped to solicit a response that would allow me to work further in trying to assist him, but he does seem to want to start at the beginning :(


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://520702]
Approved by sgifford
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (7)
As of 2014-08-01 06:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (257 votes), past polls