Creating a Dedicated Server Session

Obviously, you will need to create a server before the client. Without the server, what exactly could the client do? In practice, you may find working on both the client and server portions of the code in tandem beneficial. That model will be followed here, but before you get to that point, you have to meet a "bare minimum" standard of working. You can define this as being able to host a dedicated session and having a client connect. So now you can get started with your server.

The majority of dedicated server applications pick an Internet port that they (and only they) run. For example, Web servers almost always listen on port 80 for any Web requests. FTP servers use port 21. Only one application may listen to any given port at one time, so it's common for the application to pick a unique port to run with. The first thousand ports are considered "reserved," but you may feel free to use any available port to listen on.

For this dedicated server application, you should pick a port you feel comfortable using. The code in the text will use port 9798 to listen on. There won't be any options for the server; it will just run and update its status via the UI. The only action the server will be able to perform other than what you program into it will be shutting down.

Naturally then, you'll want a windows form for the UI status update. Go ahead and create a windows form application, and make sure your references and using clauses have been defined for DirectPlay. You will want a form with a fixed dialog border style and a label. The label can be set to a dock mode of fill so that it covers the entire form.

You will first need a declaration for the server object (which, as mentioned earlier, is similar to the peer object):

 private Server connection = null; 

You will need to add the initialization function. Since it's not possible for a server object to connect to any other session, there is no need to have a Boolean parameter for this method. Add the method found in Listing 19.1 to your application.

Listing 19.1 Initializing a Server
 public void InitializeServer() {     // Create our server object     connection = new Server();     // Check to see if we can create a TCP/IP connection     if (!IsServiceProviderValid(Address.ServiceProviderTcpIp))     {         // Nope, can't, quit this application         MessageBox.Show("Could not create a TCP/IP service provider.", "Exiting",             MessageBoxButtons.OK, MessageBoxIcon.Information);         this.Close();     }     // Create a new address for our local machine     Address deviceAddress = new Address();     deviceAddress.ServiceProvider = Address.ServiceProviderTcpIp;     deviceAddress.AddComponent(Address.KeyPort, SharedCode.DataPort);     // Set up an application description     ApplicationDescription desc = new ApplicationDescription();     desc.SessionName = "MDX Book Server Session";     desc.GuidApplication = SharedCode.ApplicationGuid;     desc.Flags = SessionFlags.ClientServer | SessionFlags.NoDpnServer;     try     {         // Host a new session         connection.Host(desc, deviceAddress);         // We can assume after the host call succeeds we are hosting         AddText("Currently Hosting a session.");     }     catch     {         AddText("Hosting this session has failed.");     } } 

You'll notice that this is similar to the hosting method for your peer session. The definitions for the IsServiceProviderValid and AddText methods aren't provided here, since they were already provided in the previous chapter. There are three significant changes in this section of code that didn't exist in the peer-to-peer session, though.

First, you'll notice that the port component has been added to the address. The yet-to-be-defined SharedCode.DataPort constant has been used for the port. Since the client (as well as the server) will require this constant, you should create a separate code file that will be used for both the server and client code bases. Create a new code file that will be used to share code between the server and client:

 public class SharedCode {     public static readonly Guid ApplicationGuid = new Guid         (15741039, 1702,1503,178, 101, 32, 13, 121, 230, 109, 59);     public const int DataPort = 9798; } 

For now, you'll notice that there are two constants included here. Each of these constants will be needed by both the client and server. In the peer-to-peer session, the peer code was encapsulated in a single executable, so this "sharing" of code wasn't necessary. Since you will have separate executables for the client and server here, this shared code is necessary.

The last major change is the flags you're using for the application description. The flags for ClientServer and NoDpnServer are being used for the application. The first flag is relatively self-explanatory. You want this session to be a client/server session. The second flag, however, requires a little more explaining.

As discussed earlier, only a single application may listen on a given port at any given time. You cannot have two applications each trying to listen on port 9897, for example. The first call will succeed, and the second (and each subsequent) call will fail, so long as the first application is still listening on that port. However, running multiple servers on a machine, even on the same port, is a scenario that is supported by DirectPlay.

To facilitate this behavior, DirectPlay has an external application, "dpnsrv.exe ", that is spawned whenever a session is created for the first time. This application's only job is to be the one application that is listening to the specified port (or the default port if none is specified) and forwarding any client enumerations to the correct "real" host. While potentially useful in some scenarios, it isn't recommended that you use this application for your session. Using the NoDpnServer flag informs DirectPlay not to use the "dpnsrv.exe " application, and you will handle everything yourself.

Before you are ready to have the server up and running, you will need to make sure you call the initialization method, as well as making sure you dispose your connection object when the application quits. Update your main method as follows:

 static void Main() {     using (Form1 frm = new Form1())     {         frm.Show();         frm.InitializeServer();         Application.Run(frm);     } } 

You will also need to update the disposing override for your form and add the following code to dispose your connection object:

 if (connection != null)     connection.Dispose(); 

In order to see the difference between using the NoDpnServer flag and not using it, first compile your application and run it. You should see your status inform you that you are hosting a session. Now run the application a second time, without closing the first instance. You should be informed that hosting the session has failed. This is because the second instance was trying to listen on a port that was already opened for listening by another application. Now, remove the flag and try the same steps. You can now successfully host two instances of your server. In order to be "dedicated," though, you will only ever want one. Place the flag back in your code.



Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net