Let's Talk About Threads
BlitzMax Forums/BlitzMax Beginners Area/Let's Talk About Threads
| ||
So I'm sitting here scratching my head on how threads will benefit network code. Obviously if each player has it's own thread on the server that would be a bonus. The server listens on a specific port for incoming connections. When a request is made it connects the client and starts the client it's own thread. So now we have the server app running and a client thread. The client thread is listening to and sending packets to that specific client. So how would the client thread interface with the server app? I'm guessing you're trying to avoid the whole looping through a list of players to see if a packet has arrived. So you'd have to make it so the client is listening and when a packet arrives it just forces the packet into the server via some means. Hmm...May have a packetqueue on the server app that is set to 0 and when the client thread has a packet it adds it to the packetque and sets a variable to true so the server knows a packet is there. No looping through all clients. Just have to figure that one out. Pseudo-code: While Not KeyHit(KEY_ESCAPE) Local clientID% = server.isPacketWaiting() If clientID then server.ProcessPacket(clientID) Flip 0 Wend End Type TServer field Max_Players% Field ClientList:TList Field ClientThread:TThread[] Field isPacketWaiting% Function Create:TServer(maxPlayers%=32) Local s:TServer = New TServer s.Max_Players = maxPlayers s.ClientList = New TList s.ClientThread = [maxPlayers] Return S End Function End Type Type TClient Field id% Function Create:TClient() Local c:TClient = New TClient c.id = GetFreeId() Return c End Fuction End Type |
| ||
Warning: Threading with Network code runs the risk of denial of service attacks... I would be thinking about that while you code it. I would most definitely want to queue the requests, otherwise your network code could swallow your game/program. You would likely want a thread for packet arrival and either another for processing or a time-limited loop in the main program. Packet arrives and goes to queue if queue is not full packets get processed during packet processing time As far as client / server goes I think you might be mixing apples and oranges. a client connects to the server over the network, the server serves the client. If you are hosting the client and the server on the same box then you would likely want to create an alternate path for those packets to get to the server rather than sending anything over the network. |
| ||
So you have the main server app and then one separate thread that's listening for new packets. Wait, but why not one thread per client that's just listening for that one specific client? Is that overkill? |
| ||
Ok I'm thinking that there has to be an optimal number of threads to run. And do threads soley rely on how many cores a processor has? If 4 threads is optimal then I can just split the number of clients among the 4 threads evenly. That way it's like 4 servers running and each is only serving a limited number of clients. The main server app would just monitor the threads to make sure everything was running ok. If you had 16 players and 4 threads, that's 4 clients per thread. Each thread receives a packet from the 4 players assigned to it but it broadcasts the packet back out to all players excluding itself. Here's the new pseudo-code: |
| ||
Here's something new.'TServer2 '8 players over 2 threaded servers Local server:TServer = TServer.Create(8,2) Graphics 800,600,0 While Not KeyDown(KEY_ESCAPE) server.Listen() Flip 0 Wend EndGraphics End Type TServer Field numClients%, maxClients% Field maxClientsPerServerThread% Field numServerThreads%, maxServerThreads% Field ServerThreadList:TList = New TList Field MasterClientList:TList = New TList Function Create:TServer(maxClients%, maxServerThreads%) Local s:TServer = New TServer s.maxClients = maxClients s.maxServerThreads = maxServerThreads s.maxClientsPerServerThread = maxClients / maxServerThreads s.numServerThreads = 0 Return s End Function Method Listen() 'Listen for New Connections Local data = Connection.SocketListen() If data then server.ConnectClient(data) End Method Method ConnectClient(data) 'Here's where we assign the new client to a ServerThread 'If there are no ServerThreads available, we create a new one If Self.numClients < Self.maxClients 'Ok there's room for this guy, let's connect him Self.numClients :+ 1 Else 'No dice, the game is too popular...start your own server Endif End Method Method AddServerThread() Local st:TServerThread = New TServerThread Self.ServerThreadList.AddLast( CreateThread( st.Run() ) ) End Method End Type '------- Type TServerThread Field id%, state% Field maxClients% Field numClients% Field ClientList:TList Function Create:TServerThread(id%, maxClients%) Local st:TServerThread = New TServerThread st.id = id st.maxClients = maxClients st.ClientList = New TList Return st End Function Method Run() Repeat Local client:TClient For client = Eachin Self.ClientList Local data = client.Listen() If data Then BroadCast(server.MainClientList Next Until Self.state = 0 End Method End Type '------- Type TClient Field id% Method Send(packet:TPacket) WriteBank packet End Method End Type Type TPacket Field data:TBank End Type Function BroadCast(client:TList, excludeIP%) End Function |