Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

How to introduce threading in socket communication

by simonz (Sexton)
on Oct 03, 2013 at 06:43 UTC ( #1056724=perlquestion: print w/ replies, xml ) Need Help??
simonz has asked for the wisdom of the Perl Monks concerning the following question:

Hi
I have written a client-server program, where the client continuously sending some message after an interval. But now I want this to be done in a 2-threaded mechanism, where every new connection should start a new thread to accept the data.
The main thread will always accept the new connection and every thread will try to append to a shared variable say $shared_data. And the main thread will attempt to read from that shared_data from the beginning of it.
On the other hand every client should randomly send some data of some particular pattern (eg. delimited by a string 'EOM'). Every thread getting this info should write it to the shared variable everytime when 'EOM' arrives. The main thread will look for the 'EOM' in the shared data and remove it till then by locking and unlocking the shared data.
I need some help on programming this with thread. How in the server code , I will introduce the following threading mechanism to accomplish this

$thr = threads->create(\&worker_thread);
Below is my client server code
# Server #
use IO::Socket; use IO::Select; use strict; my $server = IO::Socket::INET::->new(Proto => 'tcp', LocalPort => 55555, Listen => 1, Reuse => 1 ) or die "Server can't start: $!" +; my $readable_handles = new IO::Select(); $readable_handles->add($server); my $buf; while (1) { # select() blocks until a socket is ready to be read or written my ($new_readable) = IO::Select->select($readable_handles, undef, undef, 0); # If it comes here, there is at least one handle # to read from or write to. For the moment, worry only about # the read side. foreach my $sock (@$new_readable) { print "Inside foreach $sock \n"; if ($sock == $server) { my $new_sock = $sock->accept(); # Add it to the list, and go back to select because the # new socket may not be readable yet. $readable_handles->add($new_sock); } #- server part else { #print STDERR "Reading...\n"; # It is an ordinary client socket, ready for reading. $buf = <$sock>; if ($buf) { #- print the buffer print "Read $buf\n"; # .... Do stuff with $buf } else { # Client closed socket. We do the same here, and remove # it from the readable_handles list $readable_handles->remove($sock); close($sock); } } } }
# client #
use IO::Socket; my $client = IO::Socket::INET::->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => 55555 ) or die "Client can't connect: $!"; my @msgs = 1 .. 100; for (@msgs) { print $client "$_\n"; sleep 1; }

Comment on How to introduce threading in socket communication
Select or Download Code
Re: How to introduce threading in socket communication
by BrowserUk (Pope) on Oct 03, 2013 at 14:22 UTC

    Without looking at the details too closely, your server already appears to support concurrent clients via IO::Select.

    What are you hoping to gain by adding threading to the mix?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.

      The data received by the server will be send to a Tk gui to update some gui row. The gui will have 50k of row of HList widget and some 20k of those row will be simultaneously changing. Without thread the gui is hanging and not scrollable and usable. Hence trying to introduce thread so that the gui does not hang and stays unaffected when thousands of its rows are changing itself.

        Without thread the gui is hanging and not scrollable and usable. Hence trying to introduce thread so that the gui does not hang ...

        Then why does the OP talk of "But now I want this to be done in a 2-threaded mechanism, where every new connection should start a new thread to accept the data."? (Besides that saying "a 2-threaded mechanism" and "every new connection should start a thread" in the same sentence is very confused; and that the OP code showing nothing to do with Tk.)

        You have a concurrent server which could be wrapped up into a function.

        1. Start a thread and run that function in it.
        2. Create a Thread::Queue and have the server thread post the received data onto it.
        3. Run the gui in the main thread and start a periodic timer that checks the queue (say) every 10th of a second, dequeues what it finds and adds it to your gui.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.
Re: How to introduce threading in socket communication
by golux (Pilgrim) on Oct 13, 2013 at 16:22 UTC
    Hi simonz,

    The following is a very basic example. It's important to note that the perl/Tk code isolated from any thread functionality, since perl/Tk itself is NOT thread-safe.

    Your client and server code have been made into their own threads, essentially unmodified. The only changes were to chomp the incoming buffer to the server from the client, and to push it onto the shared server_msgs array so it can be visible to the Tk program.

    #!/usr/bin/perl -w # # Shows a very basic example of perl thread usage, simultaneous with # perl/Tk code. Note that perl/Tk (which is NOT thread-safe) *must* # be kept isolated from any thread functionality. # # References: # http://www.perlmonks.org/?node_id=1056724 # # 2013-10-13 golux ############### ## Libraries ## ############### use strict; use warnings; use threads; use threads::shared; use Tk; use Tk::ROText; ################## ## User-defined ## ################## my $tk_title = 'perl/Tk with threads (basic example) - 2013-10-13 gol +ux'; ############## ## Globals ## ############## my @server_msgs : shared; share(@server_msgs); ################## ## Main Program ## ################## my $thread1 = threads->create(\&server_thread)->detach; my $thread2 = threads->create(\&client_thread)->detach; create_tk_gui(); ################# ## Subroutines ## ################# #===================# ## Tk Main Program ## #===================# sub create_tk_gui { my $mw = new Tk::MainWindow(-title => $tk_title); my $top = frame($mw, 'B'); my $f1 = frame($top, 'x'); my $f2 = frame($top, 'B'); my $b1 = tk_pack($f1->Button(-text => 'Exit (^X)', -bg => 'cyan') +, '>'); my $txt = tk_pack($f2->ROText(-bg => '#ffefb2'), '^B'); my $h = { 'mw' => $mw, 'text' => $txt }; $b1->configure(-command => sub { exit }); $txt->insert("1.0", "[Server Messages]\n"); $mw->bind('<Control-x>' => sub { $b1->invoke }); $mw->repeat(250 => [ \&gui_loop, $h ]); $mw->MainLoop; } sub frame { my ($w, $pack, @args) = @_; my $frame = $w->Frame(@args); return tk_pack($frame, $pack); } sub tk_pack { my ($w, $pack) = @_; my $h_fill = { qw[ n none x x y y b both ] }; my $h_side = { qw[ < left > right ^ top v bottom ] }; $pack ||= '^n'; my $side = ($pack =~ s/^([<>^v])//)? $1: '^'; $pack ||= 'n'; my $fill = lc $pack; my $exp = ($fill eq $pack)? 0: 1; $fill = $h_fill->{$fill}; $side = $h_side->{$side}; $w->pack(-expand => $exp, -fill => $fill, -side => $side); return $w; } sub gui_loop { my ($h) = @_; if (0 == @server_msgs) { return; } my $txt = $h->{'text'}; while (@server_msgs) { my $msg = shift @server_msgs; $txt->insert('end', "$msg\n"); } } #=================# ## Server Thread ## #=================# sub server_thread { print "[Server]\n"; use IO::Socket; use IO::Select; use strict; my $server = IO::Socket::INET::->new(Proto => 'tcp', LocalPort => 55555, Listen => 1, Reuse => 1 ) or die "Server can't start: + $!"; my $readable_handles = new IO::Select(); $readable_handles->add($server); my $buf; while (1) { # select() blocks until a socket is ready to be read or written my ($new_readable) = IO::Select->select($readable_handles, undef, undef, 0); # If it comes here, there is at least one handle # to read from or write to. For the moment, worry only about # the read side. foreach my $sock (@$new_readable) { print "Inside foreach $sock \n"; if ($sock == $server) { my $new_sock = $sock->accept(); # Add it to the list, and go back to select because the # new socket may not be readable yet. $readable_handles->add($new_sock); } #- server part else { #print STDERR "Reading...\n"; # It is an ordinary client socket, ready for reading. $buf = <$sock>; if ($buf) { chomp $buf; #- print the buffer # print "Read $buf\n"; push @server_msgs, "Read $buf"; # .... Do stuff with $buf } else { # Client closed socket. We do the same here, and remove # it from the readable_handles list $readable_handles->remove($sock); close($sock); } } } } } #=================# ## Client Thread ## #=================# sub client_thread { print "[Client]\n"; use IO::Socket; my $client = IO::Socket::INET::->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => 55555 ) or die "Client can't connect: $!"; my @msgs = 1 .. 100; for (@msgs) { print $client "$_\n"; sleep 1; } }
    say  substr+lc crypt(qw $i3 SI$),4,5

      # sub server_thread { print "[Server]\n"; use IO::Socket; use IO::Select; use strict; my $server = IO::Socket::INET::->new(Proto => 'tcp', LocalPort => 55555, Listen => 1, Reuse => 1 ) or die "Server can't start +: $!"; my $readable_handles = new IO::Select(); ... # It is an ordinary client socket, ready for reading. $buf = <$sock>; ...

      Using buffered IO reads with an IO::Select server is fundamentally flawed. If any one client sends a packet that doesn't contain the right delimiter -- whether through programmer error; or because the user aborts the client mid-transmission; or because tcp decides to fragment the packet at an inappropriate point -- then your server will hang indefinitely.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (8)
As of 2014-12-20 20:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (98 votes), past polls