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

Hello,

Here's my setup: One host that listens on a $hostportin for incomming connections. There can be at most $n connections. When a connection is started between a host and a client the host needs to be able to send and receive information from this client, any previous clients, as well as be avaiable to start new connections with other clients. (Sounds like a HTTP Daemon, doesn't it).

Originally I was using sockets: host listens on $hostportin. Once a connection is started, the host sends a string to the client on that port telling the client which ports to use for sending and receiving, in essence defining two ports for each client to use. If there are, say, 5 clients, that's 10 ports + the original $hostportin, that need to be managed at all time. There has to be a better way than this! Can anyone please suggest some further reading or at least point me in a better direction? Thank you.

Replies are listed 'Best First'.
Re: Networking with Perl
by rdfield (Priest) on Sep 06, 2002 at 12:56 UTC
    Lincoln Stein wrote a very good book on the subject. It's called "Network Programming with Perl", and it's available from all good bookstores (and some rubbish ones too).

    rdfield

Re: Networking with Perl
by KM (Priest) on Sep 06, 2002 at 12:55 UTC
    Have you looked at the Net::* modules on the CPAN? Or IO::Socket? The Perl Cookbook has an example of a pre-forking server (you should be able to find it on the web as well), and the book Network Programming with Perl would also give you much clue.

    Cheers,
    KM

Re: Networking with Perl
by valdez (Monsignor) on Sep 06, 2002 at 13:41 UTC

    I think that Net::Server is exactly what you are looking for. Here it is a little quote from its description:

    Net::Server is an extensible, generic Perl server engine. Net::Server combines the good properties from Net::Daemon (0.34), NetServer::Generic (1.03), and Net::FTPServer (1.0), and also from various concepts in the Apache Webserver.

    Net::Server attempts to be a generic server as in Net::Daemon and NetServer::Generic. It includes with it the ability to run as an inetd process (Net::Server::INET), a single connection server (Net::Server or Net::Server::Single), a forking server (Net::Server::Fork), a preforking server which maintains a constant number of preforked children (Net::Server::PreForkSimple), or as a managed preforking server which maintains the number of children based on server load (Net::Server::PreFork). In all but the inetd type, the server provides the ability to connect to one or to multiple server ports.

    HTH. Ciao, Valerio

Re: Networking with Perl
by jepri (Parson) on Sep 06, 2002 at 14:17 UTC
    It sounds like you might be a little confused on the networking thing. When a client connects to your server, you accept the socket and store a reference to that socket in a variable. You can then access that socket any time you want, to read or write, via the variable. You never need to worry about the port again.

    Once you have accepted the connection, you can go back to listening on the original port - the kernel takes care of all the details. So everytime you accept a connection, you can just add the socket to an array or a hash, and keep track of them like any other variable.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

      What you are saying is true. However, following my original example, 5 connections will still mean 11 open sockets at all times. I was looking to do it somehow else. Maybe, for example, have a single method that would send a string to a particular IP adress / port number of a particular client, thus illiminating the need for at least 5, or maybe even 10 of those 11 sockets.
        However, following my original example, 5 connections will still mean 11 open sockets at all times.

        So don't follow your original example.

        I was looking to do it somehow else.

        I told you how to do it 'somehow else'. I don't get it. You ignored what I wrote, then demanded the answer I gave you, while insisting on continuing on doing it the wrong way. Do you work for MicroSoft?

        Pay attention this time:

        • Sockets are bidirectional. YOU DO NOT NEED TWO PER CONNECTION.
        • You don't need to manage ports. The kernel does it for you already. STOP DOING IT YOURSELF.

        ____________________
        Jeremy
        I didn't believe in evil until I dated it.

Re: Networking with Perl
by sauoq (Abbot) on Sep 07, 2002 at 07:01 UTC

    As jepri said so clearly, sockets are bidirectional. So, using two for each client is really a waste unless you have a real good reason for it. Note: one for sending and one for receiving is not a good reason. I can only think of one common example where such a scheme is used. FTP uses separate control and data connections. Then again, FTP pretty much sucks as a protocol.

    Also as jepri said, you don't need to instruct your clients to use all sorts of different ports. A server can handle multiple connections to a single port. Really, you can think of the port as simply part of the address for the server. Its a useful abstraction that permits many different servers to run on a single box.

    A web server for example generally runs on port 80 and can handle multiple clients at once without telling them to come back and meet it on another port. A web server might not be an obvious example because the requests are so short that you might think it handles them sequentially but that's not the case. Either take my word for it or consider telnet servers, IRC servers, MUDs, sshd, etc, etc, etc. instead.

    So, finally, lets figure out what you should be doing. You want to have a server listening on $port. You want clients to connect to $port. You want the server to then "hold a conversation" with the client.

    If that's all you want to do, then you should probably have your server fork in which case the parent will answer more incoming connections to $port and the child will handle the client's request. In this scenario, the server is never really "managing" more than one client connection at a time.

    On the other hand, if there has to be some shared state between clients (as is the case in IRC or MUDs) then you'll need to handle multiple client connections in the server. Please notice the language I am using. You don't manage multiple ports, you manage multiple connections. Moving on, if this is the case, you'll need to use select() or IO::Select. The general idea is that you loop and occassionaly check to see if your clients sent data, if they have you read the data, and if you can, you do something with it. If you have data to send to the client, you just do so. For various reasons, this tends to be a lot stickier to code than a forking server. The good news is you probably don't really need to do it. Forking servers are best for many applications.

    Now the real question... What do you want your server to actually do? Without knowing this, we can't very well recommend how to do it.

    -sauoq
    "My two cents aren't worth a dime.";