You certainly don't need to use threads. Threads work OK if your platform is Windows, but for what you need a select()-based interface is preferable.
IO::Select (and other similar modules) allow you to watch one or more sockets (usually instances IO::Socket::INET) to see whether data is available for reading, the outgoing socket buffer isn't full, or whether the sockets are disconnected.
You simply have a loop with a call to select() passing some reasonable timeout (say 50 milliseconds).
On the client side you want to be able to read and write at the same time. Buffer reads from the client into a scalar variable until the buffer contains a newline (or whatever is your end-of-message marker). Don't write to the server until you have a complete message.
If you want it to look like IRC, you'll probably have to update the screen nicely somewhere during that select() loop. There's only one thread so you've no worries about multiple threads drawing at the same time. That means you can't use simple reading functions or <STDIN>; take a look at Term::ReadKey to see how to get one key at a time.
On the server you'll also need a select() loop, but instead of one socket, you'll have a socket for each connected client. Also, you'll have a listen socket in the select-group which will be available for reading when a client is connecting (you should call accept()).
Buffer both reads and writes from each client separately. When you get a full message from a client, prepend it to the write buffer of all clients (don't skip the sender :-).
Add some logic on the client and server for cleanly disconnecting (and perhaps noticing when the connection goes away due to errors) and you're done.
-David
Update: oops, that "can" must've been confusing :-) |