SunQuest
           C Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsProgramming LanguagesC Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
Stay one step ahead of the competition. Evaluate and give feedback on some of the hottest web development tools on the market today. Make your opinion heard! Click Here
  #1  
Old April 18th, 2003, 04:14 PM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
Sockets, Network Progging, etc...

- our newest project is to "do something with UDP clients/servers"(very descriptive project, huh? lol). So, i decided that i would take my TicTacToe program from a month ago and make it so 2 people could play each other over the net. Im thinking of having each client player send their "move" to the server, having the server then transmit the move as an integer to the other client. I decided it would be much easier to have the move verification done on the client side rather than sending the move and then checking it.
What im debating now is whether i need to make the server multi threaded or not? It wont be accepting simultaneous input, so i was thinking probably not... any thoughts on this?

edit: normally i would bother my teacher with this, but the jerk off doesnt answer my emails for some reason, maybe he is mad at me for crashing his server program (even tho i wrote a fix for it after i did, as it didnt deal with my 300+ character strings too well)

edit2: hmm, i m thinking that threads might be a must here, at least on the client sides. otherwise i wont be able to make the user's wait for their turn... any comments welcome plz, im still in my pseudo code phase here

Last edited by infamous41md : April 18th, 2003 at 05:12 PM.

Reply With Quote
  #2  
Old April 18th, 2003, 05:41 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793 dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level) 
Time spent in forums: 1 Month 6 h 53 m 57 sec
Reputation Power: 434
A networked game already? I assume that you've already gone through the echo client/server phase, so you've gotten the basics under your belt.

I don't think that the server would need to be multithreaded, especially since it's using UDP. TCP I would think should be, but not UDP. That's assuming that you don't want the server to do anything else between packets except to listen for the next packet, whereupon it immediately processes it and sends out its responses.

Normally, a UDP client only receives a message from the server immediately after having sent a message. However, here you intend the clients to received unsolicited messages from the server. That being the case, I think that a multithreaded client would make sense. That way, it can remain responsive to the user at the same time it's listening for incoming traffic.

BTW, there are other ways for handling the listening-sockets problem. You could use non-blocking sockets. You could use select(), especially if you are monitoring multiple sockets (and even stdin under Linux, but not under Winsock). Just something to keep in mind as you expand your studies.

You realize that besides using UDP, you will also have to define an application-layer protocol for the game. It's almost like a chat room app. The players will need to log on so that the server can know their IP addresses. Similarly, they will need to be able to log out. They will need to let the server know to start a game, as well as what their move is. And the server will need to send them the game status. Also, because UDP is "shoot and forget", you might need to implement an acknowledgement mechanism to ensure that packets are getting through; eg, if the server does not acknowledge receipt of a move, the client will resend it up to so many times before declaring loss of communication with the server.

Lincoln Stein did something similar in his "Network Programming with Perl" book. There, the example was a chat room. One of the good things about his book was that he went through a number of different kinds of servers (eg, multithreaded, select, pre-forking) and discussed their strengths and weaknesses. If it's in the library or the bookstore (I haven't seen it about lately), you might want to browse through it.

Let us know how it turns out!

Reply With Quote
  #3  
Old April 18th, 2003, 06:09 PM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
Quote:
Originally posted by dwise1_aol
A networked game already? I assume that you've already gone through the echo client/server phase, so you've gotten the basics under your belt.


-heh, yes rather quickly i ran thru this. my teacher had set up a UDP server that would listen for client messages, upon receipt of one it would echo back the string in uppercase. originally he had it so the client could only send a string of maximum length, so me being devious, decided to change the maxBufferLength on my client and see what happened when i sent him a nice big string. needless to say i got no response from my string, and no responses from any further ones. so i took a look at his server program and realized it would close the socket and terminate if it recieved any errors(too large, etc), so i rewrote the server side to deal with the errors and send back an insulting message to the perpetrator, . so thanks to that, i think i have a decent understanding of how this all works.
Quote:
Originally posted by dwise1_aol

You realize that besides using UDP, you will also have to define an application-layer protocol for the game. It's almost like a chat room app. The players will need to log on so that the server can know their IP addresses. Similarly, they will need to be able to log out. They will need to let the server know to start a game, as well as what their move is. And the server will need to send them the game status. Also, because UDP is "shoot and forget", you might need to implement an acknowledgement mechanism to ensure that packets are getting through; eg, if the server does not acknowledge receipt of a move, the client will resend it up to so many times before declaring loss of communication with the server.

-yes, my current tic tac toe game is well layered, (thankfully my teacher stressed to us the importance of reusability), i have an AppModel class that weaves together the gameEngine, my WndProc, and some other stuff i 4get. one thing that i have noticed that is odd, in this code:
Code:
if (nBytesRecvd == SOCKET_ERROR)
    {
//       char tmp[] = "don't try to crash my server u haxx0r!!";
//	   strcpy(buffer,tmp);
	   nBytesSent = sendto (
           hSocket,
           buffer,
           strlen(buffer) + 1,
           NO_FLAGS_SET,
           (LPSOCKADDR) &ClientSockAddr, // holds client addr: IP, port


- ClientSockAddr this is stored in an odd way. for example, when i debug and watch it in the window, it will give addresses as: 1728161984 , when the ip is 192.168.1.10(2) <- or 3 or 4
my idea to deal with messages was to store this address for each computer, and then when the server recieves a message, it will send to the address that it didnt recieve the from? make sense? i couldnt think how else to send moves to the right person

Reply With Quote
  #4  
Old April 18th, 2003, 07:34 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793 dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level) 
Time spent in forums: 1 Month 6 h 53 m 57 sec
Reputation Power: 434
Quote:
Originally posted by infamous41md

- ClientSockAddr this is stored in an odd way. for example, when i debug and watch it in the window, it will give addresses as: 1728161984 , when the ip is 192.168.1.10(2) <- or 3 or 4


No, that's right. Remember that the IP address is four octets, each of which take up one byte (the term "octet" was coined before "byte" was set to 8 bits; I first encountered the word "octet" in the LISEZMOI (readme) file for a French freeware app). What you are reading there is the decimal representation of that 4-byte integer; you'd be able to pick out each octet if you read it in hex.

Which brings us to another problem, byte-order. 1728161984 is 6701A8C0 in hex -- 67 = 103, 01 = 1, A8 = 168, C0 = 192. On an Intel machine, host byte order is the reverse of network byte order. That is why when you set the port number in the in_addr struct you pass it through htons(), which translates a short integer from host order to network order. The same should be done on both client and server side for integer data in the payload. Obviously, inet_addr() does this for you with the IP address.

Quote:
Originally posted by infamous41md

- [b]my idea to deal with messages was to store this address for each computer, and then when the server recieves a message, it will send to the address that it didnt recieve the from? make sense? i couldnt think how else to send moves to the right person


The server should have some way of knowing who's playing the game, which is why I mentioned that as part of the game protocol. The thing is that the client doesn't even have to know explicitly what its own IP address is. In the recvfrom() function, you also get the address struct of who had sent the message. So if the client logs on as Xorciser, the server would then save the Xorciser name and associate it with the fromAddr that it got from recvfrom(). Then later when it receives a move from a player, the server can send the move to all the other players except for the one it received it from.

Edit: Oops! Looks like that's what you were describing.
However, another thought is that the server will be running the game and informing the players of changes in the game state. The server would probably still want to send the originating player an update as well, which could also serve as an ACK of the move message. Of course, this depends on how you design your game protocol.
PS: Remember that for me at present, this is all theory. I've thought and read about it, but I haven't had the spare time to try to put a network game together. Most of my networking projects so far have been more work-related. Guess I was born a few decades too early.

BTW, if you really want to know what your own IP address is, you can get it via gethostname() followed by gethostbyname(). Trouble is that you then have to deal with the hostent struct, which I had had a bit of trouble researching at first.

Fun! Fun! Fun!

Last edited by dwise1_aol : April 18th, 2003 at 07:44 PM.

Reply With Quote
  #5  
Old April 18th, 2003, 09:39 PM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
ah, yes, now i understand the ip address thing, wasnt thinking for a minute there. so far i wrote almost the entire client side and it has all compiled correctly, now onto the server side. having the server run the game was just too crazy for me to even think about, since it's only a simple game i think running it this way should work alright. i decided to abandon the thread idea because frankly my head started spinning every time i tried to think about what i was going to suspend and when it would resume... i'm hoping its all going to work out, basically the user isnt going to be able to do anything while waiting to recieve the other player's move. i am going to take your advice of having the server send an ACK message to whomever sent the message...hopefully this will all work out, but i have a feeling im going to have some intense debugging sesssions, ah well,thanks for the advice

edit: umm, problem, this has to do with what u mentioned above in regards to recognizing clients, this:

if(ClientSockAddr.sin_addr == Client1.sin_addr )
yields this error C2678: binary '==' : no operator defined which takes a left-hand operand of type 'struct in_addr
-which was what i expected to happen, but how do i go about comparing these, or as u said, associating a name with a client?

Last edited by infamous41md : April 18th, 2003 at 10:10 PM.

Reply With Quote
  #6  
Old April 18th, 2003, 11:56 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793 dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level) 
Time spent in forums: 1 Month 6 h 53 m 57 sec
Reputation Power: 434
Quote:
Originally posted by infamous41md
edit: umm, problem, this has to do with what u mentioned above in regards to recognizing clients, this:

if(ClientSockAddr.sin_addr == Client1.sin_addr )
yields this error C2678: binary '==' : no operator defined which takes a left-hand operand of type 'struct in_addr
-which was what i expected to happen, but how do i go about comparing these, or as u said, associating a name with a client?


It doesn't like it that you're trying to compare a struct to a struct.

sin_addr is of type struct in_addr, which is defined as:
Code:
struct in_addr
{
    unsigned long s_addr;  /* IP address (32 bits) */
};

if(ClientSockAddr.sin_addr.s_addr == Client1.sin_addr.s_addr )
should work.

The address structures look pretty weird and convoluted at first and all that typecasting looks like a needless pain, but there's a good reason for it -- or at least good intentions. I forget right now which header file it's in (on UNIX at least; on Windows, it must be in the Winsock.h file), but there's a list of tens of address families and protocol familes that sockets is meant to support. The address scheme is intended to support all of them.

As for associating a player with an IP address, I was thinking along the lines of an array of structs, each element of which contains the player name, IP address, and whatever other player information you need.

Reply With Quote
  #7  
Old April 19th, 2003, 11:12 AM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
beautiful!!!!!!!!!!!!!! it all compiles correctly! now comes the real test, if u dont hear from me in a few hours, either:

a) it worked beautifully and im out having a good time drinking some beer and barbecuing some food
b) my computer "mysteriously" decided to throw itself into a wall

Reply With Quote
  #8  
Old April 19th, 2003, 01:03 PM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
miserable linkage errors

test1client.obj : error LNK2001: unresolved external symbol _htons@4
test1client.obj : error LNK2001: unresolved external symbol _inet_addr@4
test1client.obj : error LNK2001: unresolved external symbol _socket@12
test1client.obj : error LNK2001: unresolved external symbol _WSAStartup@8
test1client.obj : error LNK2001: unresolved external symbol _recvfrom@24
test1client.obj : error LNK2001: unresolved external symbol _WSACleanup@0
test1client.obj : error LNK2001: unresolved external symbol _closesocket@4
test1client.obj : error LNK2001: unresolved external symbol _sendto@24

-what's up with ^^ this?

edit: i have defined my client as a class. with a header and a cpp file. for some reason this is causing the error i guess, b/c i have rebuilt it prolly 3 times now from the original .cpp file(one that works) without changing a single thing.

Last edited by infamous41md : April 19th, 2003 at 02:03 PM.

Reply With Quote
  #9  
Old April 19th, 2003, 02:28 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793 dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level) 
Time spent in forums: 1 Month 6 h 53 m 57 sec
Reputation Power: 434
It looks like you're not linking in the Winsock library. Is this a different project, because I thought you had just gotten it to make.

What development system are you using? I know from the .obj file that it's not g++.

If it's Visual C++, then open the Projects Settings dialog box (Main Menu | Projects | Settings). Click on the Link tab. In the Object/Library Modules edit box, you should have added wsock32.lib .

Of course, if you're using a different development system, you'll need to do whatever is needed to add the winsock library to the link step (it may be named differently).

Reply With Quote
  #10  
Old April 19th, 2003, 02:56 PM
infamous41md's Avatar
infamous41md infamous41md is offline
not a fan of fascism (n00b)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Feb 2003
Location: ct
Posts: 2,756 infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level)infamous41md User rank is Sergeant (500 - 2000 Reputation Level) 
Time spent in forums: 2 Days 11 h 4 m 29 sec
Reputation Power: 26
-same project, i had everything compiled separately, but then when i actually built them in the same project i got that garbage.

-msvc++, yep adding that worked like a charm. any clue as to why?

edit: wow, this incredibly hard to debug. cant debug client and server at same time...aghhhhh!! i need another computer next to mine so i can do both. now i have to pick which one to just exe and which to debug, what a pain.

Last edited by infamous41md : April 19th, 2003 at 03:39 PM.

Reply With Quote
  #11  
Old April 19th, 2003, 03:48 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793 dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level)dwise1_aol User rank is Lieutenant Colonel (40000 - 50000 Reputation Level) 
Time spent in forums: 1 Month 6 h 53 m 57 sec
Reputation Power: 434
Quote:
Originally posted by infamous41md
-same project, i had everything compiled separately, but then when i actually built them in the same project i got that garbage.


Just a matter of personal preference and style. As I add files to a project, I just run the make instead of compiling each one separately while developing it. Either way works. Though it does lead to sloppy terminology; we'll say that it compiles when actually we mean that it made.

Quote:
-msvc++, yep adding that worked like a charm. any clue as to why?

It's a basic library thing. The code behind the library function calls resides in the .lib files. If we linked all that code in to every project, then all our programs would be larger than 41.5 MB (I just did a dir on the VC++ lib directory). Since no program I've ever encountered uses each and every of those library functions, that's a huge waste of storage space and of memory (both of which used to be very expensive -- in 1978 8KB of RAM cost about $220, ten years ago 1 MB of RAM was incredibly cheap at $50).

So all that library code is carved up into separate library files and if your code calls a function in a library file, then it needs to link in that library. Also, this way somebody, even yourself, can create a library of special-purpose functions, such as OpenGL, and distribute the code as library files and header files (another alternative is as DLLs and header files). The only requirement for the user of a library is to include the header files in his source and to link the library into his project. Since most programs do not do networking, Winsock is pulled off as a separate library and make must be told to link it in.

When you run the App Wizard, it normally will also pull in the libraries that you need, according to your choices. Did you create a Wizarded Windows app or an empty console app that you then filled yourself? I normally do the latter, so I have to explicitly add wsock32.lib to the project. A PDF file my site links to describes this process: "Transitioning from UNIX to Windows Socket Programming" by Paul O'Steen at http://cs.baylor.edu/~donahoo/pract...dowsSockets.pdf .

So now that it makes an executable, how does it work?

Reply With Quote
  #12  
Old April 19th, 2003, 03:56 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is online now
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,793