Friday, October 16, 2009

An Internet Chat System
























Network
Programming with Perl
By
Lincoln D. Stein
Slots : 1
Table
of Contents
Chapter 19.  UDP
Servers






    Content







An Internet Chat System


This chapter develops a useful UDP version of
an Internet chat system. Like other chat systems that might be
familiar to you, the software consists of a server that
manages multiple discussion groups called "channels." Users
log into the server using a command-line client, join whatever
channels they are interested in, and begin exchanging public
messages. Any public message that a user sends is echoed by
the server to all members of the user's current channel. The
server also supports private messages, which are sent to a
single user only by using his or her login name. The system
notifies users whenever someone joins or departs one of the
channels they are monitoring.


A Sample Session


Figure
19.1 shows a sample session with the chat client. As
always, keyboard input is in a bold font and output from the
program is in normal font.



Figure 19.1. A
session with the chat client


We begin by invoking the client with the name
of the server to connect to. The program prompts us for a
nickname, logs in, and prints a confirmation message. We then
issue the /channels command
to fetch the list of available channels. This client, like
certain other command-line chat clients, expects all commands
to begin with the " / " character. Anything else we
type is assumed to be a public message to be transmitted to
the current channel. The system replies with the names of five
channels, a brief description, and the number of users that
belong to each one (a single user may be a member of multiple
channels at once, so the sum of these numbers may not reflect
the total number of users on the system).


We join the Weather channel using the class=docEmphStrong>/join command, at which point we
begin to see public messages from other users, as well as join
and departure notifications. We participate briefly in the
conversation and then issue the class=docEmphStrong>/users command to view the users
who currently belong to the channel. This command lists users'
nicknames, the length of time that they have been on the
system, and the channels that they are subscribed to.


We send a private message to one of the users
using the /private command,
/join the Hobbies channel
briefly, and finally log out using class=docEmphStrong>/quit.


In addition to the commands shown in the
example (Figure
19.1), there's also a class=docEmphStrong>/part command that allows one to
depart a channel. Otherwise, the list of subscribed channels
just grows every time you join one.


Chat System Design


The chat system is message oriented. Clients
send prearranged messages to the server to log in, join a
channel, send a public message, and so forth. The server sends
messages back to the client whenever an event of interest
occurs, such as another user posting a public message to a
subscribed channel.


Event Codes

In all our previous examples, we have passed
information between client and server in text form. For
example, in the travesty server, the server's welcome message
was the text string "100." However, some Internet protocols
pass command codes and other numeric data in binary form. To
illustrate such systems, the chat server uses binary codes
rather than human-readable ones.


In this system, all communication between
client and server is via a series of binary messages. Each
message consists of an integer event code packed with a
message string. For example, to create a public message using
the SEND_PUBLIC message constant, we call
pack() with the format "na*":

$message = pack("na*",SEND_PUBLIC,"hello, anyone here?");

To retrieve the code and the message string,
we call unpack() with the same format:

($code,$data) = unpack("na*",$message);

We use the " n " format to pack the
event code in platform-independent "network" byte order. This
ensures that clients and servers can communicate even if their
hosts don't share the same byte order.


The various event codes are defined as
constants in a .pm file that is
shared between the client and server source trees. The code
for packing and unpacking messages is encapsulated in a module
named ChatObjects::Comm. A brief description of each of the
messages is given in Table
19.1.























































































Table 19.1. Event
Codes
class=docEmphasis>Code class=docEmphasis>Argument class=docEmphasis>Description
ERROR <error
message>
Server reports an
error
LOGIN_REQ vAlign=top><nickname> Client requests a
login
LOGIN_ACK vAlign=top><nickname> Server acknowledges
successful login
LOGOFF vAlign=top><nickname> Client signals a
signoff
JOIN_REQ <title>
Client requests to
join channel <title>
JOIN_ACK <title>
<count>
Server acknowledges
join of channel <title>, currently
containing <count> users
PART_REQ <title>
Client requests to
depart channel
PART_ACK <title>
Server acknowledges
departure
SEND_PUBLIC
<text>
Client sends public
message
PUBLIC_MSG
<title>
<user> <text>
User
<user> has sent message
<text> on channel <title>
SEND_PRIVATE
<user>
<text>
Client sends private
message <text> to user
<user>
PRIVATE_MSG
<user>
<text>
User
<user> has sent private message
<text>
USER_JOINS
<channel>
<user>
User has joined
indicated channel
USER_PARTS
<channel>
<user>
User has departed
indicated channel
LIST_CHANNELS
  Client requests a list
of all channel titles
CHANNEL_ITEM
<channel>
<count> <desc>
Sent in response to a
LIST_CHANNELS request
    Channel
<channel> has <count>
users and description <desc>
LIST_USERS
  Client requests a list
of users in current channel
USER_ITEM <user>
<timeon> <channel 1> <channel
2>...<channel n>
Sent in response to a
LIST_USERS request. User <user>
has been online for <timeon> seconds and
is subscribed to channels <channel 1>
through <channel n>


User Information

The system must maintain a certain amount of
state information about each active user: the channels she has
subscribed to, her nickname, her login time, and the address
and port her client is bound to. While this information could
be maintained on either the client or the server side, it's
probably better that the server keep track of this
information. It reduces the server's dependency on the
client's implementing the chat protocol correctly, and it
allows for more server-side features to be added later. For
example, since the server is responsible for subscribing users
to a channel, it is easy to limit the number or type of
channels that a user can join. This information is maintained
by objects of class ChatObjects::User.


Channel Information

One other item of information that the server
tracks is the list of channels and associated information. In
addition to the title, channels maintain a human-readable
description and a list of the users currently subscribed. This
simplifies the task of sending a message to all members of the
channel. This information is maintained by objects of class
ChatObjects::Channel.


Concurrency

We assume that each transaction that the
server is called upon to handle�logging in a user, sending a
public message, listing channels�can be disposed of rapidly.
Therefore, the server has a single-threaded design that
receives and processes messages on a first-come, first-served
basis. Messages come in from users in any order, so the server
must keep track of each user's address and associate it with
the proper ChatObjects::User object.


On the other end, the client will be
communicating with only one server. However, it needs to
process input from both the server and the user, so uses a
simple select() loop to multiplex between the two
sources of input.


The object classes used by the server are
designed for subclassing. This enables us to modify the chat
system to take advantage of multicasting in the next
chapter.









       




    Top

    No comments:

    Post a Comment