Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95

    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 :D (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 06:12 PM.
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    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!
  4. #3
  5. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    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, :D . so thanks to that, i think i have a decent understanding of how this all works.
    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
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    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.

    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 08:44 PM.
  8. #5
  9. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    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 11:10 PM.
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    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.
  12. #7
  13. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    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
  14. #8
  15. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95

    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 03:03 PM.
  16. #9
  17. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    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).
  18. #10
  19. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    -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 04:39 PM.
  20. #11
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    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.

    -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/practi...owsSockets.pdf .

    So now that it makes an executable, how does it work?
  22. #12
  23. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    Originally posted by infamous41md
    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.
    Yep, this is the fun part now.

    I don't usually go straight into the debugger, but rather use other techniques first.

    Trace statements. For instance, in the server I'll have it print out a message (I'm running this in console mode) that says, for example, that I received a packet of this length from this IP address and the contents of the packet are this (usually in hex, unless I'm working with text data). That way, I'll know whether the networking is going on or not.

    Pardon this stupid question, but I assume that you know that you don't need two computers to do networking. You can very easily run the server and a client on the same machine; eg, open two DOS windows, start up the server in one, and run the client in the other. Just address the server at localhost (which is address 127.0.0.1).

    Also, had you picked up a packet sniffer yet? That can help if you find yourself not knowing whether the client is not sending or the server is not receiving.
    Last edited by dwise1_aol; April 19th, 2003 at 04:58 PM.
  24. #13
  25. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    Pardon this stupid question, but I assume that you know that you don't need two computers to do networking. You can very easily run the server and a client on the same machine; eg, open two DOS windows, start up the server in one, and run the client in the other. Just address the server at localhost (which is address 127.0.0.1).

    - question fully pardoned :D (as there are no stupid questions) i did know this, i meant debugging both at the same time. i have the server side and client side as different projects. and from what i know, i didnt think it was possible to debug 2 separate projects at the same time.

    Also, had you picked up a packet sniffer yet? That can help if you find yourself not knowing whether the client is not sending or the server is not receiving.

    - i had to put my packet sniffing interests on hold a day or so after that thread b/c of some schoolwork i had. i was playing around with tcpdump in linux, but im programming this in msvc++ on XP. actually, the client is sending and the server is recieving correctly, at least when im only using one client; right now im just working out some of the logic in processing the data.
  26. #14
  27. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    haha this has truly gotten crazy now!!! no problem connecting and setting up the game...BUT, the server sends messages to the opposite client in regards to moves, but since im running both clients from my computer its not working. one client sends a message and then goes into recieve mode, and they both get back the move even tho one already has that space on the board covered, LOL MUST GET MORE COMPUTERS!! guess this will have to wait until i get into the school lab.
  28. #15
  29. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    How are you handling port assignments?

    The server should have done a bind() to be able to "listen" on a specific port that the clients could know about ahead of time (the "listening" is done with a recvfrom; listen() is for TCP). With the from-address parameter of the recvfrom, the server knows who sent the message and to whom to send a response, if necessary. The server's address and port number have already been associated to that socket with the bind().

    Even if you don't use bind(), the socket still gets bound to a port. The only difference is that you can't predict which port that'll be. The system somehow picks any old free port and binds it to the socket.

    That tells me that even though you are running two instances of the same client, both of which are talking to the same server port, they should each be bound to a different port. So the server shouldn't have any problem distinguishing between the two clients.

    So if both clients are getting the message, I would think that means that the server is sending out two messages. It might help to have the server output a trace statement every time it receives and sends a message and from/to which client. If the server is not a console app, you could write the trace statements to a text file. That should help you see what's being sent and when.


    Otherwise, the problem is probably in the game protocol, in which case even three different computers wouldn't help. You said you were implementing the ACK response to a move. Could that be messing you up?
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo