There's a nice chapter on that subject in the book "Game Programming with Python" by Sean Riley. You will find all the background information that you need there. Even if you are not going to use Python itself, the book will be very useful.
In C# or Java apps, you will mostly find the "concurrent threaded server" model being implemented, meaning that there will be a worker thread for every connected client. The main reason for this is that the applications are using blocking I/O sockets.
In BlitzMax, however, you could implement a "concurrent asynchronous server", which Sean Riley describes as the "reactor pattern". It is a single-process, single-threaded server. Which basically is something like this baby here that I started a while ago:
It's a base skeleton for an NNTP server and not doing much. I have a fully working "concurrent threaded server" version written in C# on (the leftovers of) my homepage.
Personally, I no longer think that in this domain (network servers) the multithreaded approach has any benefits over the single-threaded approach. Multi-threading itself does not solve any scalability problems, but instead it creates a whole set of new issues: CPU usage and "ghost" threads being just two examples.
As for the rest of your question, you are talking about something like "Second Life" here. I have read in the German c't magazine that they have around 50 people on one server at a time. They also use one server per zone in their "world"; if you leave a zone, they use object persistency, transfer the object to a new server and "revive" it there. At least that is what Miguel de Icaza wrote in his blog a while ago. Second Life actually uses Mono as the server framework, that's why Miguel wrote about it.
Anyway. I think it gives an idea about the size of the server farm that one can expect for a full blown MMO project. It simply is to big for an low-budget one-man shop...
In C# or Java apps, you will mostly find the "concurrent threaded server" model being implemented, meaning that there will be a worker thread for every connected client. The main reason for this is that the applications are using blocking I/O sockets.
In BlitzMax, however, you could implement a "concurrent asynchronous server", which Sean Riley describes as the "reactor pattern". It is a single-process, single-threaded server. Which basically is something like this baby here that I started a while ago:
'* '* Digital Nomad News Server '* '* Author: Winfried Maus '* '* '*==================================================================================================================================== SuperStrict Const NNTP_PORT:Int = 119 Const MAX_CMD_PARAMS:Int = 10 GetServer().Create() GetServer().Run() End Function GetServer:NomadServer() Global Nomad:NomadServer = New NomadServer Return Nomad End Function '*==================================================================================================================================== '* This class defines the worker instance For successful '* NNTP connections. '* Type NNTPServer Field NNTPSocket:TSocket Field NNTPStream:TSocketStream Field dbConnstring:String = "/Users/Winni/DigitalNomad.dat" Field currentGroup:String = "" Field currentArticleNum:Long = 0 Field lastKnownArticleNum:Long = 0 Field article:String Field posting:Int = False Field ihavetransfer:Int = False Field postingallowed:Int = True Field serverpostingallowed:Int = True Field articleToPost:String = "" Field cmd:String Field cmdParam:String[] = New String[MAX_CMD_PARAMS] Field cmdParamCount:Int = 0 Field running:Int Field TimeOutTime:Int = GetTimeNumeric() Field localConnection:Int = False Method wmsendMessage( message:String ) WriteLine( NNTPStream, message ) End Method Method cmdHelp() wmsendMessage( "100 List of recognized commands follows." ) wmsendMessage( "Help" ) wmsendMessage( "List" ) wmsendMessage( "Group" ) wmsendMessage( "Post" ) wmsendMessage( "Slave" ) wmsendMessage( "Mode reader | stream" ) wmsendMessage( "XOver" ) wmsendMessage( "XHDR" ) wmsendMessage( "Article" ) wmsendMessage( "Stat" ) wmsendMessage( "Head" ) wmsendMessage( "Body" ) wmsendMessage( "Last" ) wmsendMessage( "Next" ) wmsendMessage( "Ihave" ) wmsendMessage( "Newgroups" ) wmsendMessage( "Newnews" ) wmsendMessage( "Date" ) wmsendMessage( "Quit" ) 'Show administrative commands only on Local connection If localConnection wmsendMessage( "XShutDown" ) wmsendMessage( "XDeleteMessage msgid articleid" ) wmsendMessage( "XCreateGroup groupname [y | n]" ) wmsendMessage( "XDeleteGroup groupname firstarticle lastarticle" ) wmsendMessage( "XPosting server | groupname y | n" ) End If wmsendMessage( "." ) End Method Method clearParams() For Local nPos:Int = 0 To cmdParam.Length - 1 cmdParam[nPos] = "" Next cmd = "" cmdParamCount = -1 End Method Method MessageHandler( message:String ) clearParams() While message.Length > 0 And cmdParamCount < MAX_CMD_PARAMS Local spcpos:Int = message.Find(" ") If spcpos = -1 spcpos = Len( message ) End If If cmdParamCount = -1 cmd = Upper( Left( message, spcpos ) ) Else cmdParam[cmdParamCount] = Upper( Left( message, spcpos) ) End If If spcpos + 1 <= message.Length message = Right( message, Len( message ) - spcpos - 1 ) Else message = "" End If cmdParamCount :+ 1 Wend Select cmd Case "HELP" cmdHelp() Case "QUIT" running = False Case "XSHUTDOWN" If localConnection GetServer().ShutDown() Else wmsendMessage( "500 Local connection required." ) End If Default wmsendMessage( "500 Command not recognized." ) End Select End Method Method Create ( pSocket:TSocket, pStream:TSocketStream ) NNTPSocket = pSocket NNTPStream = pStream If SocketRemoteIP( NNTPSocket ) = SocketLocalIP( NNTPSocket ) localConnection = True End If running = True If serverpostingallowed wmsendMessage( "200 Welcome to the Digital Nomad News Server (BlitzMax version)." ) Else wmsendMessage( "201 Welcome to the Digital Nomad News Server (BlitzMax version), read only." ) End If End Method Method GetTimeNumeric:Int() Local Now:String = CurrentTime() Return Left(Now,2).ToInt() * 3600 + Mid(Now,4,2).ToInt() * 60 + Right(Now,2).ToInt() End Method Method Run() Local Now:Int = GetTimeNumeric() '* Exception for midnight... If Now = 0 Now = 1 TimeOutTime = 86400 - TimeOutTime End If '* Check incoming stream If Eof( NNTPStream ) running = False Else If SocketReadAvail( NNTPSocket ) > 0 MessageHandler( ReadLine( NNTPStream ) ) TimeOutTime = GetTimeNumeric() Else '* Idle for more than 5 minutes, close this connection. If Now >= TimeOutTime + 300 running = False wmsendMessage( "500 Timeout: Connection idle for more than five minutes." ) End If End If EndIf If Not running wmsendMessage( "500 Bye." ) CloseStream( NNTPStream ) CloseSocket( NNTPSocket ) End If End Method End Type '*==================================================================================================================================== '* Main Application Class '* Type NomadServer Field ShuttingDown:Int = 0 Field ServerSocket:TSocket = New TSocket Field WorkerSocket:TSocket Field WorkerStream:TSocketStream Field NNTPobj:NNTPServer Field NNTPObjects:TList = New TList Method Create() ServerSocket = CreateTCPSocket() If Not BindSocket( ServerSocket, NNTP_PORT ) Print "Bindsocket failed. Now quitting." End EndIf SocketListen( ServerSocket ) Print "Listening." End Method Method ShutDown() ShuttingDown = 1 End Method Method Run() While ShuttingDown < 3 '* When still running normally, accept new incoming connections. If ShuttingDown = 0 WorkerSocket = SocketAccept( ServerSocket ) If WorkerSocket <> Null WorkerStream = CreateSocketStream( WorkerSocket, True ) NNTPobj = New NNTPServer NNTPobj.Create( WorkerSocket, WorkerStream ) NNTPObjects.AddLast NNTPobj WorkerSocket = Null WorkerStream = Null EndIf End If '* When shutting down is initialized, do this in a separate loop to make sure that all connections will be closed properly. If ShuttingDown = 1 For NNTPobj=EachIn NNTPObjects NNTPobj.running = False Next ShuttingDown = 2 End If '* Iterate through all open connections. For NNTPobj=EachIn NNTPObjects NNTPobj.Run() If Not NNTPobj.running ListRemove( NNTPObjects, NNTPobj ) End If Next If ShuttingDown = 2 ShuttingDown = 3 End If Wend End Method End Type '*==================================================================================================================================== '* EOF
It's a base skeleton for an NNTP server and not doing much. I have a fully working "concurrent threaded server" version written in C# on (the leftovers of) my homepage.
Personally, I no longer think that in this domain (network servers) the multithreaded approach has any benefits over the single-threaded approach. Multi-threading itself does not solve any scalability problems, but instead it creates a whole set of new issues: CPU usage and "ghost" threads being just two examples.
As for the rest of your question, you are talking about something like "Second Life" here. I have read in the German c't magazine that they have around 50 people on one server at a time. They also use one server per zone in their "world"; if you leave a zone, they use object persistency, transfer the object to a new server and "revive" it there. At least that is what Miguel de Icaza wrote in his blog a while ago. Second Life actually uses Mono as the server framework, that's why Miguel wrote about it.
Anyway. I think it gives an idea about the size of the server farm that one can expect for a full blown MMO project. It simply is to big for an low-budget one-man shop...