I agree that 'select' is the traditional (and fastest and probably best etc) way to do this, but I fancy talking about this a bit (to put my own thoughts straight if nothing else).
You are writing a case of an application which would like to do I/O on more than one source at a time. I/O is slow (compared to almost everything else) and so the normal interface the operating system offers you is that when you request some I/O it puts your process to sleep until the I/O completes. (This is called 'blocking' I/O). It doesn't matter whether you are doing a read or write from a file or a socket or whatever (OK - so there are special cases, but we mostly care about these ones). The reason it does this is to more efficiently share resources amongst many processes on one system.
In your case (and in many other important cases, e.g. many network server applications) you want to get on with doing other things whilst your I/O chugs away, but come back to your I/O whenever it needs care and attention (more data, or finish things off).
You can generally ask for your read or write operations to be performed in a 'non-blocking' way, in which case they simply fail with an 'EAGAIN' error until the operating system has enough data to give you a chunk (read) or enough buffer space to accept a chunk from you (write).
If you aren't careful the above leads you down the road of the 'busy loop' which is annoying. You can put in your own 'sleep' calls but since your program won't be woken up from the sleep when the operating system is ready for you to do I/O, you waste a bit of time (otherwise known as the all-important 'latency') before responding.
The original Unix answer to this is 'select'. This allows your process to sleep for a (short or long) timeout until one of your file descriptors (your handle to some I/O) is ready for action. If you wake up from your timeout and there is no I/O to do, you can have a quick go at performing some other chores and then go back to your select. This is a "select loop".
Another way of handling the situation is to use threads. These can raise strong passions in people both for and against but lets not go there right now. The problem of blocking operations was (I think) one of the major original rationals behind threads. The idea is that you can spawn a new thread to handle the blocking I/O whilst the rest of your program gets on with things. Only one thread is blocked (or 'monopolised') by the I/O and so everything is hunky dory.
Well it obviously isn't that simple and adding threads gives you a new set of challenges, not least in perl where there are a significant number of 'gotchas', in theory if not in practice, to the use of threads. But you see how some people at least might like this programming paradigm.
NB. Your idea of using 'fork' is related to this idea of using threads. Each non-blocking I/O stalls a 'thread of execution'. In the 'fork' model these are two processes, in the threading model they are two threads. In both cases the unpleasantness comes from how these two "threads of execution" share memory and avoid stomping on each other.
Windows NT systems support 'select' but native Win32 implementations would do better to use 'WaitForMultipleObjects' (or whatever it is called) which is broadly similar but more in tune with the way NT does things.
Also, 'select' has some problems scaling up to lots and lots of file descriptors and so a 'poll' call is supported by modern Unices. This is broadly similar to select (and doesn't do any 'polling' really, it does put you to sleep until activity occurs) but scales better to larger numbers of file descriptors.
Lastly, on Linux (and I'm sure on other modern Unices) there are funky things like real time signals delivered when async I/O (another name for non-blocking I/O) completes.
So, as has already been said, the simple answer to your question is 'select' (or 'fork' and some interprocess memory sharing or similar unpleasantness) - but you touch on an important area of interest to people doing high performance server work.
Sorry for the rant. Some of the above interfaces will be easily acessible from perl some won't. I don't advise using the 'select' function call natively, instead use IO::Socket. Much easier.
Bye.