Top Mud Sites Forum Return to TopMudSites.com
Go Back   Top Mud Sites Forum > Mud Development and Administration > MUD Coding
Click here to Register

Reply
 
Thread Tools
Old 08-19-2004, 06:32 AM   #1
Khadgar
New Member
 
Join Date: Mar 2003
Posts: 29
Khadgar is on a distinguished road
I posted a message here a few months ago stating I was starting to write my own codebase using c++; thus far, it has been a long tedious task, but things have been progressing smoothly.  Recently, I have been trying to get my program to work with telnet, zMud, and other clients.  I probably should not have waited this long to start programming the socket code.  Nevertheless, i dont think it will be that hard to get my automapper and everything working again once this socket code is in place.

I have no problem connecting to one computer anywhere in the world.  However, I dont -completely- understand how a program can communicate with multiple users instantaneously.  Although I've read briefly about a few techniques i could possibly use, im not sure which direction to take.  Multithreading? Asynchronous sockets? Another technique im not aware of?  Please tell me how you handle multiple user I/O.

I tried to follow the msdn example for creating a server as you can see with my modified code example below.  The only thing I dont understand is the second argument of the bind function which states (SOCKADDR*) &service.  Could somebody please explan this notation to me.  Also, please feel free to comment on the code example below as suggestions for improvement are always welcome.  

[code]
//NOTE; Don't forget to link the library WS2_32.lib

#include <winsock2.h>
#include <windows.h>
#include <iostream>

using namespace std;

int main()
{
   WSADATA wsaData;

   //Initialize winSock2
   int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);

   if (iResult != NO_ERROR)
   {
       cout << "WinSock2 initialization; Error Code " << iResult << endl << endl;
   }
   else
   {
       //Create a socket and validate if successful
       SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

       if (m_socket == INVALID_SOCKET)
       {
           cout << "Socket Error; " << WSAGetLastError() << endl << endl;
       }
       else
       {
           //Bind the socket
           sockaddr_in service;
           service.sin_family = AF_INET;
           service.sin_addr.s_addr = inet_addr("127.0.0.1");
           service.sin_port = htons(7500);

           //Listen for and accept connections on the socket if binding was successful
           if (bind(m_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
           {
               cout << "Binding Error; " << WSAGetLastError() << endl << endl;
               closesocket(m_socket);
           }
           else if (listen(m_socket, 1) == SOCKET_ERROR)
           {
               cout << "Error listening on the socket." << endl << endl;
           }
           else
           {
               SOCKET AcceptSocket = SOCKET_ERROR;
               cout << "Waiting for a client to connect..." << endl << endl;
             
               while (AcceptSocket == SOCKET_ERROR)
               {
                   AcceptSocket = accept(m_socket, NULL, NULL);
               }
       
               cout << "Client Connected!" << endl << endl;
               m_socket = AcceptSocket;
           }   //end inner if statement
       }   //end middle if statement
   }   //end outer if statement

   return 0;
}   //end function main  
[/quote]

Basically, I need to create some sort of loop that handles connection requests as well as multiple user input at the same time.  Code examples and any help will be greatly appreciated.  Also, please concider this code in the public domain; anybody who wishes to modify it and use it has my blessings.  Thank you all once again  
Khadgar is offline   Reply With Quote
Old 08-19-2004, 09:49 AM   #2
Darrik
New Member
 
Join Date: Apr 2002
Posts: 25
Darrik is on a distinguished road
I highly recommend you read Beej's Guide to Network Programming, available online ( Search in google ).  It is a very clear tutorial covering most if not all of everything you need to know about network programming.

The bind function takes a SOCKADDR*, while service is a sockaddr_in.  Beej explains the difference between the two.  Look it up so I don't have to .  (SOCKADDR*) &service casts service to SOCKADDR* so that the function will take that argument without compiler errors.  gcc may take it without casting with a smile, but g++ will not.

Darrik Vequir
Darrik is offline   Reply With Quote
Old 08-19-2004, 11:59 AM   #3
Razzer
New Member
 
Join Date: Jan 2003
Posts: 3
Razzer is on a distinguished road
Quote:
Originally Posted by
I have no problem connecting to one computer anywhere in the world. However, I dont -completely- understand how a program can communicate with multiple users instantaneously. Although I've read briefly about a few techniques i could possibly use, im not sure which direction to take. Multithreading? Asynchronous sockets? Another technique im not aware of? Please tell me how you handle multiple user I/O.
The simplest would just be a linear socket pattern. It roughly goes something like this

Create server socket (somewhat like you have)
Loop while game is running
Check sockets (look up select())
If new connection is waiting, accept connection
Read new data, parse, and send output.
End loop

Something similar to that pattern. Multithreading might be a challenge that you might not want to take if you don't fully understand BSD sockets. Using asynchronous socket on a TCP stream is unwise, so scratch that option.

Quote:
Originally Posted by
The only thing I dont understand is the second argument of the bind function which states (SOCKADDR*) &service. Could somebody please explan this notation to me.
It is a bit of a hack. The second paramenter of bind() takes a struct sockaddr pointer. In order for many different socket family and types to be used, different structures (like sockaddr_in) need to be cast to a struct sockaddr pointer.

[code] service.sin_addr.s_addr = inet_addr("127.0.0.1");[/quote]

Instead of inet_addr("127.0.0.1"), you'd probably be better off with INADDR_ANY.

[code] m_socket = AcceptSocket;[/quote]

You won't want to do this in a real MUD. This reassigned the variable m_socket with AcceptSocket, so it completely loses whatever value it had before. The problem is that the value it had before was the descriptor to the server you had just made, and by the reassignment you have lost the server descriptor.
Razzer is offline   Reply With Quote
Old 08-20-2004, 10:23 AM   #4
Kastagaar
Member
 
Join Date: Apr 2002
Location: Hampshire, UK
Posts: 117
Kastagaar is on a distinguished road
Send a message via Yahoo to Kastagaar
The multiplexing function you are looking for (and is found in the above tutorials) is "select()". It takes arguments including sets of socket file descriptors, and tells you which of those has data that can be read without blocking the program flow.
Kastagaar is offline   Reply With Quote
Old 08-22-2004, 08:14 PM   #5
Khadgar
New Member
 
Join Date: Mar 2003
Posts: 29
Khadgar is on a distinguished road
Beej's Guide to Network Programming was really useful as Darrik mentioned.  I must admit I was a little turned off at the thought of coding sockets at first, but it isn't as hard as I thought it would be.  I suppose the disadvantage with using the select() function would be it takes longer than multithreaded applications because it processes one request at a time.  Nevertheless, i think it will work quite well on an efficient server.

Thanks to those who responded with my first set of questions.  However, I have a few more questions regarding networking:

1)  Is there a way to determine a client's screen width and height?  If so, how would I go by doing this?  

2) Is there a way to get and set a client's console cursor position?  I'd like to have the automapper and room description side by side without recoding them.  

3) How would you go by coloring characters over a network?  

4) How do you prevent certain players from logging onto your server?  How exactly do you ban them?  Hostname? IP address?

I know how to do 1-3 with my own computer, but when it comes to networking, I don't know what functions to use.  Any good references or code examples will be greatly appreciated.  Once again, thanks in advance to those who help.
Khadgar is offline   Reply With Quote
Old 08-22-2004, 09:22 PM   #6
Razzer
New Member
 
Join Date: Jan 2003
Posts: 3
Razzer is on a distinguished road
Quote:
Originally Posted by
I suppose the disadvantage with using the select() function would be it takes longer than multithreaded applications because it processes one request at a time.
What do you mean? select() looks at all the sockets (well... really techy detail says otherwise, but just assume it does) it is passed.

Quote:
Originally Posted by
1) Is there a way to determine a client's screen width and height? If so, how would I go by doing this?

2) Is there a way to get and set a client's console cursor position? I'd like to have the automapper and room description side by side without recoding them.

3) How would you go by coloring characters over a network?
I assume you would be interested in more of a reference than exact code so which you can be able to write the appropiate code yourself. You can always come back and ask, but I think the reference will do you go in the long run.

So, with that said, I would check out http://sourcery.dyndns.org/. (I hope you like pink.) Click on the SocketsProgramming link on the bottom left-hand corner. Then go to the section "Terminal/ANSI". Those are references that probably should get you to a start. If you can't understand them, just go ahead and write a nasty e-mail to the site administrator on how he is unable to provide helpful links ().

Quote:
Originally Posted by
4) How do you prevent certain players from logging onto your server? How exactly do you ban them? Hostname? IP address?
Easiest way is like this:

Accept new connection.
Get IP address of connection.
Compare it to the list of banned IP addresses.
Kick if there is a match.
Razzer is offline   Reply With Quote
Old 08-23-2004, 04:44 AM   #7
Kastagaar
Member
 
Join Date: Apr 2002
Location: Hampshire, UK
Posts: 117
Kastagaar is on a distinguished road
Send a message via Yahoo to Kastagaar
Quote:
Originally Posted by
I suppose the disadvantage with using the select() function would be it takes longer than multithreaded applications because it processes one request at a time.
On the contrary. select() works on sets of sockets, so with a good design its quite possible to poll all of your inbound sockets to see who is ready to be read.

Quote:
Originally Posted by
1) Is there a way to determine a client's screen width and height? If so, how would I go by doing this?
Read up on Telnet and its NAWS option that most clients support.

Quote:
Originally Posted by
2) Is there a way to get and set a client's console cursor position? I'd like to have the automapper and room description side by side without recoding them.

3) How would you go by coloring characters over a network?
You'll need to use ANSI escape codes for these. http://www.fh-jena.de/~gmueller/Kurs...esc_vt100.html has a good list. The one you're interested in is <ESC>[6n.

Quote:
Originally Posted by
4) How do you prevent certain players from logging onto your server? How exactly do you ban them? Hostname? IP address?
Yes.
Kastagaar is offline   Reply With Quote
Old 08-23-2004, 06:47 AM   #8
Khadgar
New Member
 
Join Date: Mar 2003
Posts: 29
Khadgar is on a distinguished road
Quote:
Originally Posted by
I suppose the disadvantage with using the select() function would be it takes longer than multithreaded applications because it processes one request at a time.
Let me explain what I ment in a little more detail.  By using the select() function, all the sockets are polled and I/O is dealt with sequentially one socket at a time. The order in which input is dealt with is not necessarily the order in which it arrived in the message queue.  The amount of time it takes for the program to complete all the tasks is greater than if it had used multithreading; with multithreading, the amount of time it takes for a program to complete all the tasks is just the amount of time it takes for the program to complete the longest task.

Thank Razzer and Kastagaar for responding so quickly.  I found those references to be very useful and interesting; I looked into everything except the NAWS negotiations thus far and everything is working like a charm.  Ill probably look into NAWS negotiations after I get some sleep.  Thanks again  
Khadgar is offline   Reply With Quote
Old 08-23-2004, 08:34 AM   #9
Kastagaar
Member
 
Join Date: Apr 2002
Location: Hampshire, UK
Posts: 117
Kastagaar is on a distinguished road
Send a message via Yahoo to Kastagaar
Quote:
Originally Posted by
The amount of time it takes for the program to complete all the tasks is greater than if it had used multithreading; with multithreading, the amount of time it takes for a program to complete all the tasks is just the amount of time it takes for the program to complete the longest task.
This is only true on a machine with multiple processors. A single-processor machine (HyperThreading P4s notwithstanding) will still have to execute the threads sequentially one way or another, even if it's in a lot of tiny little sub-sequences.

Quote:
Originally Posted by
Thank Razzer and Kastagaar for responding so quickly.
Any time.
Kastagaar is offline   Reply With Quote
Old 08-23-2004, 11:51 AM   #10
Razzer
New Member
 
Join Date: Jan 2003
Posts: 3
Razzer is on a distinguished road
Quote:
Originally Posted by
Let me explain what I ment in a little more detail. By using the select() function, all the sockets are polled and I/O is dealt with sequentially one socket at a time.
Sure. However, select() has been around for a long time, and it has probably been quite optimized by most POSIX complaint systems to make select work as fast as possible.

Quote:
Originally Posted by
The order in which input is dealt with is not necessarily the order in which it arrived in the message queue.
True. However, threads wouldn't solve that problem because the read would be dependant upon which thread was lucky enough to call recv first. The closest you could come to something like that is using POSIX (fake) asynchronous sockets, which probably isn't a good idea with TCP .

Quote:
Originally Posted by
The amount of time it takes for the program to complete all the tasks is greater than if it had used multithreading; with multithreading, the amount of time it takes for a program to complete all the tasks is just the amount of time it takes for the program to complete the longest task.
Probably not. Threads eat up resources too. The more threads you use, the more resources it takes up. Too many thread will bog down the program because most of the program's time is dealing with switching between threads. Furthermore, according to Richard Stevens, multi-threading is slower than select() (on a single processor machine, of course).

Quote:
Originally Posted by
Thank Razzer and Kastagaar for responding so quickly.
You are welcome .
Razzer is offline   Reply With Quote
Old 08-23-2004, 08:02 PM   #11
karlan
Member
 
Join Date: Apr 2002
Location: Brisbane Australia
Posts: 74
karlan is on a distinguished road
Multithreading also favours players with faster connections... I consider that a bad thing, alot of my friends from school are living in remote areas with unreliable access via telephone, and ADSL or cable is just a pipe dream, and I know I would quickly stop playing a MU if I was disadvantaged that way. In addition you'll have to be very very carefull with critical section control if you multithread. It will be possible for char data to get well out of sync, if 2 threads are updating a chars health at the same time, which one will be used (or possibly both)
karlan is offline   Reply With Quote
Reply


Thread Tools


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off

All times are GMT -4. The time now is 05:04 AM.


Powered by vBulletin® Version 3.6.7
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Style based on a design by Essilor
Copyright Top Mud Sites.com 2014