more useful options | |
PerlMonks |
comment on |
( [id://3333]=superdoc: print w/replies, xml ) | Need Help?? |
I was surprised to discover how easy it was to write a fairly robust server that
will wow your friends, and impress your colleagues. Well maybe.
The IO::Socket package provides a very easy object oriented interface to the nitty-gritty details of socket control. To start, all servers need a listening socket, that is a socket to which clients connect to. Creating a listen socket is trivial: This will create a listening socket on localhost port 8000, using the tcp protocal. The 'Listen' is the max number of client requests to queue. And 'Reuse' will let you stop then start the server rebinding to port 8000. With 'Reuse=>0' it could take several minutes before the kernal allows the port to be reused. These are the basic paramaters that you will need. For the full details reference the IO::Socket perldoc pages. To actually deal will a client trying to connect, the following line will create the client socket: my $connection = $listen_socket->accept Here $connection is a socket object, which can be treated as a normal file handle. So you can print to it or read from is as a normal file handle: The last little tidbit of knowledge which is really relevent does not have to do with sockets exactly, but has to do with forking servers. When a child process dies, it does not free system resources until the parent recognizes that it is dead with a 'wait' or 'waitpid' function call. Since servers generally run a long time, and fork off many children, it becomes necessary to make sure the parent notices that children are dead If the parent does not notice then the child process will become 'zombies'. Servers generally spend most of their time at the 'accept' call just waiting for a client to connect. But the problem is that it also has to be waiting for the children to die, so how can it wait for two different things at once? Easy: signals. Whenever a child dies it sends a SIGCHLD to the parent. So our server just has to register a signal handler which calls waitpid every time the SIGCHLD is sent: An easier alternative to this is to use: $SIG{CHLD} = 'IGNORE'; This will prevent zombie processes like the above signal handling routine, but it is all implicit. No explicit signal handling is necessary. I just got a report that $SIG{'CHLD'} does not get used on Solaris but $SIG{'CHILD'} does, so if you are getting zombies on Solaris try changing CHLD to CHILD. So for the mp3 player there is not a lot to add. Basically the server starts up, then a client comes in (like xmms or mpg123) opening up a socket. Then the server forks and hands off the socket to the child process. Finally the parent goes back to listening for another client. The child will simply go into an endless loop playing random songs from your playlist until the client stops listening. The child dies when the client closes its half of the socket. To create a playlist the easy way (assuming you have mp3s on your disk) do some like: find / -name "*.mp3" > playlist.m3u Here is the server in all it glory: So now you can start up there server and connect to it with your client. I suggest xmms. In xmms just do a 'Play Location', then enter "http://localhost:8000" or whatever port you started it on. To see who is listening use netstat to look at the open connections: netstat | grep 8000 You can completely ellaborate on this code with out too much trouble. I have it hooked up at my work to play custom playlists depending on what the IP address is of the client, so my friends can listen to only the music they want to. So have fun, and remember: If you cant do it with perl it is not worth doing. Update: I removed the signal handler and set $SIG{CHLD} = 'IGNORE'. This is an easier way to prevent zombies, and from reports that I have got, the old signal hanlder failed on some versions of Solaris. Update: I added in the binmode, and the Solaris CHILD comment per dicussions in subnodes or private email. In reply to MP3 server with IO::Socket by perlmonkey
|
|