3.2. Managing a Connection
After a successful connection
is made, it can be broken by various occurrences. A well-scripted
Flash movie monitors the network status and takes appropriate action
as changes occur. This is easily done inside your
NetConnection.onStatus( ) handler, which is
notified whenever the connection status changes. When a connection is
first established, the objects and components that rely on it can
begin using it. When a connection is closed, these objects may have
to be disabled or disposed of. It is especially important that the
user doesn't experience a sudden and unexplained
loss of functionality when a network connection is dropped by the
server or lost because of a network problem.
|
A commonand sometimes difficult to debugproblem occurs
when scripts define the onStatus( ) handler
after calling the connect( ) method:
nc = new NetConnection( );
nc.connect( ); // WRONG: do this after onStatus is defined!
nc.onStatus = function (info) {
trace("info.code: " + info.code);
};
If connect( ) is called prematurely, the network
connection may be established or the connection rejected before the
onStatus( ) handler has been defined. The result
is that the messages representing those events are never returned to
the handler. The onStatus( ) method must always
be defined before the connect( ) call is made.
The preceding example should be rewritten as:
nc = new NetConnection( );
nc.onStatus = function (info) {
trace("info.code: " + info.code);
};
nc.connect( );
|
For the most part, when a connection is closed, the
info object passed to the onStatus(
) method will have a level value of
"status" and a
code value of
"NetConnection.Connect.Closed".
This will happen if the network goes down, the server disconnects the
client, the server stops, or the connection is closed using
NetConnection.close( ). It is also possible that
the level value will be
"error" and the
code value
"NetConnection.Connect.AppShutdown".
The following sections discuss how to deal with various connection
status changes.
3.2.1. Dealing with Success
When Flash establishes a connection, any streams and shared objects
that rely on the connection can be set up. Testing for the
"NetConnection.Connect.Success"
code in the onStatus( ) handler is the easiest
way to do this:
if (info.code = "NetConnection.Connect.Success") {
// Initialize and connect dependent objects and components (not shown).
}
3.2.2. Dealing with Problems
When a connection cannot be established or is lost, a number of
possible message sequences can be sent to an onStatus(
) handler:
The isConnected property of the
NetConnection object is false
when any of these events occurs. Whenever a problem occurs, you may
want your script to take action, such as informing the user. The
simplest way to deal with problems is to look at the
isConnected property in the onStatus(
) handler:
if (!this.isConnected) {
if (info.code = "NetConnection.Connect.Rejected") {
// Tell the user the connection was rejected by the application.
}
else {
// Give the user more info based on info.code and/or info.level.
}
// Clean up any objects and components that need them.
// Change state by going to another frame on the main timeline.
}
Displaying a message whenever isConnected is
false may lead to the user seeing two
messagesa reject message followed by a closed message. To
avoid displaying two messages, the onStatus( )
handler must be stopped from acting on the second message. One way to
do this is to remove the onStatus( ) handler
completely by setting the onStatus property to
null after the first message arrives. This can be
done inside the onStatus( ) method:
this.onStatus = null;
Removing the onStatus( ) handler so that no
further message processing can take place may seem like a drastic
solution. However, the onStatus property can be
reset later to a method that can handle messages. Alternatively,
another NetConnection object, with a working
onStatus( ) handler, can be created and used to
connect again. Another approach is to create an extra property of the
NetConnection object that toggles the handling
of certain messages. When messages are expected after a
connect( ) call is made or after a
"success" status message, the
property is set to true. When a connection has
been closed, the property can be set to false.
Example 3-2 shows one way to do this.
3.2.3. Closing the Connection from the Client
Another potential problem is that when you let the user close the
connection via NetConnection.close( ), the
onStatus( ) handler still receives a
"closed" status message. There is
often little point in showing this message to the user since she was
responsible for closing the connection in the first place. It may be
simpler to just change the state of the application by, for example,
moving the playhead of the main timeline. Again, a property can be
stored in a NetConnection object or the
onStatus( ) method can be set to
null, to avoid displaying a close message.
Example 3-2 uses a property named
handleCloseEvents to indicate if error and close
messages should be processed. This is just one way to write an
onStatus( ) handler using this type of flag, and
it can be altered as requirements dictate. An example that assigns
values dynamically to the onStatus property is
included in the online version of Example 3-2 (at
http://flash-communications.net).
Figure 3-1 shows the timeline for the movie used in
Example 3-2. The movie can be in one of three
states, each represented by a label at the beginning of a series of
frames. Init starts on the first frame and is
played only when the movie first loads; the Login
frame is shown when the movie is in a disconnected state and the user
can try to connect; the Connected frame is shown
when the movie is in the connected state.

The script in Example 3-2, located on frame 1 of the
Scripts layer of the main timeline, displays
user messages in a text field. The ActionScript sends the playhead to
either the Login or Connected
frame depending on the state of the network
connection.
Example 3-2. A script that handles connection-related events
// writeln( ) writes messages into a text field named trace_txt
// and is a runtime alternative to trace( ) and the Output panel.
function writeln (msg) {
trace_txt.text += msg + "\n";
trace_txt.scroll = trace_txt.maxscroll;
}
/* A simple onStatus( ) handler that moves the playhead to Login if a
* connection is closed and to Connected when a connection is established.
* User messages are written via writeln( ) into a text window.
* The this.handleCloseEvents flag is used to make sure the user never
* sees redundant messages.
*/
NetConnection.prototype.onStatus = function (info) {
// Always deal with successful connections.
if (info.code == "NetConnection.Connect.Success") {
this.handleCloseEvents = true;
writeln("Success, you are connected!");
gotoAndPlay("Connected");
}
// Handle messages when the connection is closed.
if (!this.isConnected && this.handleCloseEvents) {
if (info.code == "NetConnection.Connect.Rejected") {
writeln(info.application.message);
writeln('Did you use the username "Guest" and password "Guest"?');
}
else {
writeln("Error: Connection Closed.");
}
this.handleCloseEvents = false;
gotoAndPlay("Login");
}
// Handle remote method call errors here if you need to.
};
// Create a NetConnection object.
lobby_nc = new NetConnection( );
// Called when the Connect button in the Login frames is clicked.
function doConnect ( ) {
lobby_nc.handleCloseEvents = true;
if (lobby_nc.connect("rtmp:/testLobby/",
userName_txt.text, password_txt.text)) {
writeln("Please wait. Attempting connection...");
}
else {
writeln("Can't attempt connection. Is the URI correct?");
}
}
// Called when the Disconnect button in the Connected frames is clicked.
function doDisconnect ( ) {
// User is requesting a close so we don't handle it in onStatus( ).
lobby_nc.handleCloseEvents = false;
lobby_nc.close( );
gotoAndPlay("Login");
}
gotoAndPlay("Login");
The script listed in Example 3-2 needs an
application to which to connect. Therefore, we need a
testLobby subdirectory in the
applications directory on the server from which
the movie is downloaded. Once the directory is created, the
main.asc file shown in Example 3-3 can be placed in the
testLobby subdirectory to provide the
application with its logic. This server-side script accepts
connections only from users who log in using the username
"Guest" and the password
"Guest". Rejected
clients
are passed a message to
display to the user.
Example 3-3. Server-side script (main.asc) to accept or reject connections based on username and password
/* The application.onConnect( ) method handles each client
* connection request. In this case, users who log in
* with userName "Guest" and password "Guest" are
* allowed to connect. Other connection requests are rejected.
*/
application.onConnect = function (client, userName, password) {
if (userName == "Guest" && password == "Guest") {
client.writeAccess = ""; // Don't give write access.
application.acceptConnection(client);
}
else {
application.rejectConnection(client,
{message: "This application has refused your connection."});
}
};
Whenever a Flash movie connects to an application instance, the
onConnect( ) method of the
instance's application object is
called. The first parameter passed to onConnect(
) is always a Client object that
represents the client-side Flash movie. The remaining parameters are
the parameters passed into the connect( ) method
in the movie.
Therefore, when a client attempts to connect to the
testLobby FlashCom application, the
main.asc file shown in Example 3-3 checks the username and password passed in. A
full-fledged version could validate the username and password against
a database of valid users.
3.2.4. Using a Connection
A NetConnection object represents a network
connection within a Flash movie. Any object that communicates over a
network connection must have access to a
NetConnection object. For example, the
NetStream class requires a
NetConnection object be passed into its
constructor function:
myStream_ns = new NetStream(myNetConnection);
Working with the NetStream class is covered in
Chapter 5.
Similarly, a remote shared object's
connect( ) method must be passed a
NetConnection object:
myRemote_so = SharedObject.getRemote("SOName", myNetConnection.uri, true);
myRemote_so.onStatus = onStatusFunction;
if (myRemote_so.connect(myNetConnection)) {
trace("Connection ok so far...");
}
Macromedia designed both the NetStream and
SharedObject classes so that, with some
exceptions, they could be used as soon as a
NetConnection object was passed to them. In both
cases, the NetConnection object should be one
that has attempted to make a connection even if the connection is not
yet established. For example the process of sending data can be
started via a NetStream.send( ) or
SharedObject.send( ) method call before a
connection is established. The data is held in a queue until the
connection is made. Similarly, a NetStream
object can start the process of publishing or playing audio or video
before a connection is made. In this case, when the connection is
made, the stream will begin to publish or play.
The important exception to this is shared object data and the shared
object onSync( ) handler described in Chapter 8. As an added convenience, if
onStatus( ) handlers are not created for
SharedObject and NetStream
objects, the onStatus( ) handler of the
NetConnection with which they are associated
will be called and passed the SharedObject and
NetStream information objects. In some cases,
especially when data is sent, these conveniences are useful, but for
the most part should be avoided. It is often easier to manage an
application and provide better information to the user if objects
that depend on a network connection define their own
onStatus( ) event handlers and do nothing until
a connection is successfully made.
 |