Solved

Problem with Perl networking on Windows XP

Posted on 2010-11-24
4
231 Views
Last Modified: 2012-05-10
I have been trying to make the following code work without success. TIt is a simple thread waiting on a UDP port. There are lots of possible devices that may send packets to the port which are then simply placed in a file (not included here). I have verified that the UDP socket is created (netstat -a) and that the servver is sending packets. I ran a Windows program on the same UDP and it worked okay.

I am running on Strawberry perl, v 5.12. I am having two problems.

The first is that the can_read never fires except for timeouts. If I take it out, the recv blocks and never completes. As noted above, the sending is working and the port is open. I print out the handles in the function and the one I added is present. I also found that if I give a timeout = 0, can_read returns immediately and the whole routine loops rapidly. The documenation says a value of 0 results in a blocking call.

The second is that when I set $thread_stop (to kill the thread), Perl crashes when I execute the return. The routine I use to kill the thread, sets thread_stop and then does a join on the thread. I am using Visual Studio as my editor and it gets invoked with a runtime exception.

Can someone please look at the following code and tell me what I have done wrong? It looks fine to me and I have been fighting it for days. Thanks

sub listen_thread {

    $udp_sock = IO::Socket::INET->new(PeerAddr  => inet_ntoa(INADDR_BROADCAST),
                                      Proto     => udp,
                                      LocalPort => 48888)
      or die "socket: $@";
 
     my $s = new IO::Select($udp_sock);
     
     print "listen thread running\n";
 
     #make sure the handle is registered
    @ready = $s->handles();
    print "handles = \n";
    foreach $r (@ready)
         {
           print "han: $r\n";
         }  

#enter loop to receive packets
    while (1)
    {
        @ready = $s->can_read(5);
        print "waiting handles\n";
        foreach $r (@ready)
        {
           print "rd $r\n";
        }  
           
        #see if we should terminate the thread
        if ($thread_stop == 1)
        {
          print "listen thread terminated\n";
          $udp_sock->close;
          return 1;
        }
       
        # see if something is waiting
        print "th - $ready[0] - $udp_sock\n";      
        if ($ready[0] == $udp_sock)
        {
          print "th-r-wait\n";
          $t = $udp_sock->recv($newmsg, 1400,0);
          print "th-r-done $t\n";
        }
        else
        {
           print "listen thread timeout\n";
        }
    }
}
0
Comment
Question by:bob0206
  • 2
4 Comments
 
LVL 5

Accepted Solution

by:
group0 earned 250 total points
ID: 34918854
Is there a special reason you're trying to bind the listening socket to a remote peer address of INADDR_BROADCAST?  If you just want to listen on a single UDP port for messages and then record them, here's a version that should do what you want (IO:Select is overkill in this case):

use strict;
use threads;
use threads::shared;
use IO::Socket::INET;

our $thread_stop : shared;

sub listen_thread {
	my %socket_params;
	$socket_params{'Proto'} = 'udp';
	$socket_params{'LocalPort'} = 48888;
	$socket_params{'Timeout'} = 5;
	my $sock = IO::Socket::INET->new(%socket_params) or die("unable to open socket: $@");

	print "listening thread started\n";
	while (1) {
		my ($buffer, $socket_error);
		my ($rin, $rout, $ein, $eout) = ('', '', '', '');
		vec($rin, fileno($sock), 1) = 1;
		if (select($rout=$rin, undef, $eout=$ein, $socket_params{'Timeout'})) {
			$sock->recv($buffer, 1500);
			if ($buffer) {
				printf("received message from %s:%u - %s\n", $sock->peerhost, $sock->peerport, $buffer); 
			}
			next;
		} else {
			print "select() timeout\n";
			if ($thread_stop) {
				print "listening thread shutting down\n";
				$sock->close();
				return 1;
			}
			next;
		}
	}
}

my $thr = threads->create('listen_thread');
sleep(30);
$thread_stop = 1;
$thr->join();
print "all done\n";

Open in new window


Here's a tiny sender to test with:

use strict;
use IO::Socket;
my $response = IO::Socket::INET->new(Proto=>'udp', PeerHost=>'127.0.0.1',  PeerPort=>48888);
$response->send('sample udp message');

Open in new window


And here's the output:

listening thread started
select() timeout
select() timeout
received message from 127.0.0.1:58363 - sample udp message
select() timeout
select() timeout
select() timeout
select() timeout
listening thread shutting down
all done

Open in new window

0
 
LVL 5

Expert Comment

by:group0
ID: 35118386
Any update?
0
 
LVL 9

Expert Comment

by:Suhas .
ID: 37313535
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

919 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now