wavenator has asked for the wisdom of the Perl Monks concerning the following question:

ok i made a chat program with threads but it doesnt work as i wanted to the client cantget msg's from the server and cant send him dunno why these are the codes: client:
use threads; use IO::Socket; my $so = new IO::Socket::INET( PeerAddr => '127.0.0.1', PeerPort => 1300, Proto => 'tcp', Reuse => 1,); die "Socket Error: $!\n" unless $so; my $thread = threads->create(\&start_thread); my $thread1 = threads->create(\&start_thread1); sub start_thread { while(my $txt=<$so>){print "server : $txt";} } sub start_thread1 { while(my $msg = <STDIN>){ print $so "$msg"; } } $thread->join(); $thread1->join();
server:
use threads; use IO::Socket; my $so = new IO::Socket::INET(LocalPort => '1300', Proto => 'tcp', Listen => 10, Reuse => 1,); die "Socket Error: $!\n" unless $so; while (my $client = $so->accept()) { my $thread = threads->create("start_thread"); my $thread1 = threads->create("start_thread1"); print $so "connected\n"; sub start_thread1 { while(my $get=<$client>){print "client : $get";} } sub start_thread { while(my $msg = <STDIN>){ print $so "$msg"; } } $thread->join(); }

Replies are listed 'Best First'.
Re: chat between client and server
by moritz (Cardinal) on Oct 11, 2007 at 13:16 UTC
    Since the OP didn't describe the error behaviour properly, here is my attempt:

    The server starts OK, and as soon as I start a client the server exists silently.

    The client accepts input from STDIN and terminates silently after the second line of input.

    Update: I found one error: the server write to $so once instead of writing to $client twice. Fixing that fixes the program.

    Second update: please note that this won't work with multiple clients because in the server multiple threads try to read from STDIN at the same time.

      nicely debugging ill try to make something up thx maybe someone will solve it quicker so i am still here
Re: chat between client and server
by zentara (Cardinal) on Oct 11, 2007 at 13:44 UTC
      i've already read these topics and still hasnt find the answer
        Its a complex interaction to have multi-threaded client talking in a bidirectional manner to a mutithreaded server. To be honest, I've only seen 1 example of a multi-threaded server that worked, and that was with a forking client. You are jumping into very deep water, and you expect some simple looking scripts to have working complex functionality. I would suggest you study how the forking chat server-clients work first, before complicating it with threads.

        My first guess is that you need some IO::Select stuff in the threads.

        My second guess is that you create your threads after you create your IO::Socket object, so both threads get their own copy of the object. That probably raises havoc. I would try to create the threads before you make the IO::Socket, then share the socket filehandle with the threads thru a shared variable. Then you can have some IO::Select loop in the threads to detect when they are in a recv or send mode. You can't read when the socket is in send mode, and vice-versa.....thats called blocking.

        I don't want to discourage you from trying to figure this all out, but no one has done it before, and its for a reason. That reason is it involves alot of complex juggling of the socket filehandle, which you just sort of ignore with your simple code.


        I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: chat between client and server
by roboticus (Chancellor) on Oct 11, 2007 at 12:51 UTC
    wavenator:

    If you're running the client and server on different machines, I'd expect that it wouldn't work. If they're on the same machine, seeing the error messages would be helpful.

    Using strict & warnings might also shed some light on the subject.

    ...roboticus

      no error code and when i put the warnning and strict still no wanrnnings the problem is in the code somewhere just dunno where
        wavenator:

        I've loaded up the code, and added a couple of traces and fixed a minor bug. You're having some interaction problems with your console I/O. It works ... sort of. I've run out of time, so I'll give you back the code that I've tried, and show you the symptoms.

        First, I added some traces, so I could see what was happening--Rather than wait for successful console input, I sent a message on both the client and server side so I could see that they both sent the expected messages. Then I discovered the minor bug: you were using $so instead of $client in the server.

        Once I did that, the code started almost working. Basically, I could type some text on the server side, and it would appear on the client side. Similarly, I could type text on the client side and it would appear on the server side. But you have to alternate client & server, as successive messages aren't sent until it receives one from the other side.

        Here's the slightly modified server:

        #!/usr/bin/perl -w use warnings; use strict; use threads; use IO::Socket; my $so = new IO::Socket::INET(LocalPort => '1300', Proto => 'tcp', Listen => 10, Reuse => 1,); my $client; die "Socket Error: $!\n" unless $so; sub start_thread1 { print "thread1 started\n"; while(my $get=<$client>) { print "client : $get"; } print "thread1 ended\n"; } sub start_thread { print "thread started\n"; print $client "OK ... whaddaya want?\n"; while (my $msg = <STDIN>) { print $client $msg; } print "thread ended\n"; } while ($client = $so->accept()) { my $thread = threads->create("start_thread"); my $thread1 = threads->create("start_thread1"); # This message appears to go nowhere ... we should use $client +! print $so "connected ... whatcha want?\n"; print "connected\n"; $thread->join(); }
        And here's the client:

        #!/usr/bin/perl -w use warnings; use strict; use threads; use IO::Socket; my $so = new IO::Socket::INET( PeerAddr => '127.0.0.1', PeerPort => 1300, Proto => 'tcp', Reuse => 1,); die "Socket Error: $!\n" unless $so; my $thread = threads->create(\&start_thread); my $thread1 = threads->create(\&start_thread1); sub start_thread { print "thread\n"; while (my $txt=<$so>) { print "server : $txt"; } print "endthread\n"; } sub start_thread1 { print "thread1\n"; print $so "Client connected!\n"; while (my $msg = <STDIN>) { print $so "$msg"; } print $so "Client disconnected!\n"; print "thread1end\n"; } $thread->join(); $thread1->join();

        Unfortunately, I don't know why they're blocking. I don't use threads, so there are several possibilities: Blocking in the IO::Socket::INET module, blocking on your console I/O, console I/O interaction with threads, and others that I can't think of.

        You might want to dig through perlipc and read perlfunc for more clues. I was expecting to see read and write calls in your code, so when I initially saw it, I was wondering how on earth it was supposed to work. I also didn't see any accept() calls, but apparently the IO::Socket::INET module takes care of that since I clearly see a connection and traffic taking place.

        If I get an opportunity, I'll check into it some more after work. (Unless, of course, you've already got it solved by then....)

        ...roboticus

        wavenator:

        OK ... I'll load it up on my machine and give it a go. I've not used IO::Socket before, and I really should learn it.

        ...roboticus

Re: chat between client and server
by eric256 (Parson) on Oct 11, 2007 at 18:38 UTC

    Start it off simple. I like to build the server and telnet into it to start with. Gives you full control of the client while getting the server figured out. The following works, though i think there are probably some major issues with it memory wise. It is a nice simple start though.

    #!/usr/bin/perl use strict; use warnings; use threads; use IO::Socket; my $server = IO::Socket::INET->new(LocalPort => 1300, Proto => 'tcp', Listen => 10, Reuse => 1); die "Failed to create socket: $!\n" unless $server; my $client; sub listen_to_client { while (my $get = <$client>) { print "client: $get"; }; print "Client closed\n"; } while ($client = $server->accept()) { print "Client connected\n"; threads->create("listen_to_client"); }

    I ran it in one terminal, then telnet-ed in from two separate windows. Works like a charm.


    ___________
    Eric Hodges
      didnt get my point i didnt try to make s server program the controls more then 1 client i've tried to make server+client that chats each other without IO Blocking

        Yes, and that is what this does. The server has multiple clients connecting to it that do not block each other while waiting. After this you use the same setup to build a client. The point was to start small and add features. Single client, multiple client, non-blocking multiple client connections, etc. This already does non-blocking reads from multiple clients. Doing the same thing in a client shouldn't be much harder. For non-blocking IO i don't think you want to use threads though, I think IO::Select is a better path to take.

        Either way my point was that if you have complex client/server interactions like this, start as simple as possible adding features and testing constantly. You should then be able to pinpoint exactly where the code is broken and ask specific questions.


        ___________
        Eric Hodges