Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Multiple clients with IO::Sockets, IO::Select

by swiftone (Curate)
on Sep 08, 2000 at 18:39 UTC ( [id://31592]=perlquestion: print w/replies, xml ) Need Help??

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

This is one of my first ventures into the world of sockets....
I'm trying to through together a program that will allow multiple users to exchange information. Currently I'm picturing a server to which clients connect, but I'm not wedded to that design yet.

I've been reading through Chapter 12 of the panther book, and I'm looking at the following code:

use IO::Socket; use IO::Select; $main_socket = new IO::Socket::INET (LocalHost => 'localhost', LocalPort => 1200, Listen => 5, Proto => tcp, Reuse => 1); die "Socket not created: $!\n" unless ($main_socket); $readable_handles = new IO::Select(); $readable_handles->add($main_socket); while(1){ #select() blocks until a socket is ready to be read ($new_readable) = IO::Select->select($readable_handles,undef,undef +,0); #We now have at least one readable handle. foreach $sock (@$new_readable){ if ($sock == $main_socket){ $new_sock = $sock->accept(); #new connection, add to list. #May not be readable yet. $readable_handles->add($new_sock); } else { #check to see if socket closed $buf = <$sock>; if($buf) { #Do stuff with $buf } else { #socket was closed $readable_handles->remove($sock); close($sock); } } } }
My questions are:
  1. The next section in the book says that the filehandle blocks, but I don't understand this. Can someone restate it for me?
  2. While I'm expecting to trust my clients, I can see problems if one gets stuck in an infinite loop and sends me continuous data...how would I stop that? Particularly if I'm trying to read all the info the client sends before acting on it.
  3. This code has an infinite loop, which is obviously incompatible with a GUI. I'd like to make this a package that can be used by different UIs. I have an idea of how to do this (put the loop into subroutine, make it for a limited time rather than infinite, ditto with the select, and call it via a timed event in the calling program), but any advice on pitfalls to avoid would be appreciated.
  4. Because the clients will also be modules that can be GUI based, they'll probably be polling the server to check for status changes. Assuming the clients all sent a did-anything-change query once a second, would the above code allow everyone to get talked to, or would one client have priority over the others?
  5. This all sounds like its creating some significant network traffic...is this normal? I may just be nervous since I'm used to the mostly non-interactive web.

Replies are listed 'Best First'.
(jcwren) Multiple clients with IO::Sockets, IO::Select
by jcwren (Prior) on Sep 08, 2000 at 18:53 UTC
    1. The next section in the book says that the filehandle blocks, but I don't understand this. Can someone restate it for me?

      A blocking socket is where the read() function does not return control to your program until data arrives. A non-blocking read() will cause the read() to return to you, but with no data.
    2. While I'm expecting to trust my clients, I can see problems if one gets stuck in an infinite loop and sends me continuous data...how would I stop that? Particularly if I'm trying to read all the info the client sends before acting on it.

      Your code will have to make a determine it a client is talking too much. If they are, you could first try sending a command down the pipe to shut-up and restart. Or, more drastically, you can just close the socket, and the client will fall off.
    3. This code has an infinite loop, which is obviously incompatible with a GUI. I'd like to make this a package that can be used by different UIs. I have an idea of how to do this (put the loop into subroutine, make it for a limited time rather than infinite, ditto with the select, and call it via a timed event in the calling program), but any advice on pitfalls to avoid would be appreciated.

      Every system I've ever worked on is event driven, and has a mechanism either for your program to call their handler (like the Net::IRC module), or for you to hook your code in, where you get called on a regular basis (Windows). Some do this with timer events, some make a pass through their own event lists, and then call yours, so until an event happens, you both get about 1/2 of the processes available time.
    4. Because the clients will also be modules that can be GUI based, they'll probably be polling the server to check for status changes. Assuming the clients all sent a did-anything-change query once a second, would the above code allow everyone to get talked to, or would one client have priority over the others?

      I have to defer this one. Perhaps someone else will have a more definitive answer.
    5. This all sounds like its creating some significant network traffic...is this normal? I may just be nervous since I'm used to the mostly non-interactive web.

      This is very dependant on how *much* data you'll be sending, and over what kind of transport. 2K per second over a 33.6K modem is a fairly high rate. On a T1, it starts to be more in the noise. There are ways to determine the loading factors, and perhaps you could be dynamic. You may also find that you don't need to poll once a second, that every 5 seconds will be sufficient. But since the nature of your data isn't indicated, it's hard to make an accurate assesment.


    --Chris

    e-mail jcwren
Re: Multiple clients with IO::Sockets
by merlyn (Sage) on Sep 08, 2000 at 18:46 UTC
    You might want to look at Event, which turns the problem sideways, and in some ways, makes it easier to expand and design. Your main loop can either run the event loop at known steps, or you can have the event-loop call a piece of your main loop when it's otherwise idle.

    -- Randal L. Schwartz, Perl hacker

Re: Multiple clients with IO::Sockets
by Fastolfe (Vicar) on Sep 08, 2000 at 18:48 UTC
    1. Unless you're using non-blocking sockets, a read(FH) will block, or pause execution of your program, until it gets enough data to satisfy your request. So, read(FH, ..) will wait until there's data to be read, and then return that to your application. With non-blocking sockets, read() will return immediately, with or without data. It's up to you to use select() or check the return values to see if you got data, and if so, process it accordingly, keeping in mind that you may not have all of the data you need to complete your request. You might have half a line, for example, with the other half available in a few milliseconds.

    2. Put in a timer (via alarm perhaps) or a counter (per transaction or per byte), killing the connection if you exceed a certain threshold. A properly designed protocol will limit the lengths of commands, and kill the connection when a bad command is seen.

    3. Either construct a main() type of function to be called by the body of the application, or a one-time poll() type of function that you expect the application will call frequently. In the latter case, you could just do a select() to see if there's anything waiting, and if so, read it and process it, then return control to the application.

    4. Be sure when you're doing your select processing that you go ahead and run through the entire list of waiting sockets before saying you're done. That will ensure everyone is handled.

    5. That's probably more of a question about your higher-level design than anything else, and without more background about what your application is supposed to do, I can't offer any alternatives, but if your messages are small enough, even once a second is pretty trivial.

    There are modules out there specifically for doing these types of things behind the scenes. NetServer::Generic I think is one of them. I'm not sure how it does with non-blocking sockets, but it's a good starting point for simple client-server types of apps. Good luck.

Re (tilly) 1: Multiple clients with IO::Sockets
by tilly (Archbishop) on Sep 08, 2000 at 20:05 UTC
    If you are not wedded to any design yet, give some serious thought to whether or not you can skip the custom server and client, and just write a web interface on an internal webserver.

    http is well understood, both clients and servers are freely (and widely) available...

      If you are not wedded to any design yet, give some serious thought to whether or not you can skip the custom server and client, and just write a web interface on an internal webserver.

      My first thought, believe me. However, the client end requires lots of manipulations that could only be achieved through (shudder) javascript, there is a chat aspect to it (and we know how unfriendly the PM Chatterbox is when you can't reload the page often), and finally, I want the design to be portable to non-Unixen. (i.e. internal webserver may not be easily available).

        Even so, you could (my turn to shudder) use a protocol built on http like SOAP then build the front end client from there. As for finding an internal webserver, that is generally not a problem. On Windows I have recommended Xitami to a number of people with success. Free, easy to set up, works.

        At the least this gets you out of writing and debugging the server...

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-03-19 04:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found