20+ people 2d shooter online data issues

Started by
9 comments, last by Nettention 12 years, 7 months ago
[font="Arial,"]I am making a 2d-platformer action shooter, and I want it to be a multiplayer, capable of supporting 20+ players in one server.[/font]
[font="Arial,"] I have a NetReciever(UDP/TCP) Class intact (just a very simple UDPClient Listening, then use ONE thread to handle data and use a method to process)[/font]
[font="Arial,"], but when I have more than two connection, the server starts lagging as hell. [/font]
[font="Arial,"]I use UDP as Position/Rotation of Guns/Bullets update and TCP for joining etc.[/font]
[font="Arial,"] And i can't seem to have 2+ people in the same server, otherwise the game(server-side) will starts to lag.[/font]
[font="Arial,"] Is there any example for game networking for multiple-connection? [/font]
[font="Arial,"]Like in Terraria, it uses XNA C# too, and btw i don't want to use Live, thanks a lot.[/font]
[font="Arial,"] BTW, i see in Terraria all data is tranferred using TCP, not connectionless, won't that be slow? Thanks=DDD [URGENT][/font]
[font="Arial,"]O and at last, could someone please kindly explain to me how to make a queue of data?[/font]
[font="Arial,"]I seem cannot find any relavant articles....[/font]
[font="Arial,"]Thanks!!!![/font]
[font="Arial,"]
[/font]
[font="Arial,"]{EDIT}[/font]
[font="Arial,"]I found a comment on a website :[/font]
[font=Arial,]

I think you are making it too complicated. Just have 1 UDP socket open, and set an async callback on it. For every incoming packet put it in a queue, and set the callback again. Thats it.

make sure that when queuing and dequeueing you set a lock on the queue.

it's as simple as that and performance will be great.

R

[/font]
[/quote]

Can some please provide some examples for me? How can set the callback again?
Put the bytes recieved in a queue and process it in order? but what setting callback again means?
Sorry, i am new to networking...[font=Arial,][/font]

Advertisement
If you are lagging with 3 players then something must be very, very wrong. sad.gif

If you are on XNA I suggest using Lidgren network library:

http://code.google.c...n-network-gen3/

Has a bunch of easy to follow samples.

If you are lagging with 3 players then something must be very, very wrong. sad.gif

If you are on XNA I suggest using Lidgren network library:

http://code.google.c...n-network-gen3/

Has a bunch of easy to follow samples.


Thanks for the immediate reply!
Yes, my game is built upon XNA, but I would be really grateful if someone could
point me to some kind of tutorial or books that could clarify my mistakes...
Let me paste my NetReciever class(not actually my, cuz I use 90% of the codes from a web that i couldn't remember) here:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.ComponentModel;
using System.Net;

namespace Project_1001_Forika
{
public class NetReciever
{
public TcpListener tcpListener;
public Thread listenThread;
private Action actionToPerformTCP;
private Action actionToPerformUDP;
public UdpClient udpClient;
public Thread[] UDPThread;
TimerAction UDPPacketsCounter;
int UDPPacketsCounts;
private BackgroundWorker bkgUDPListener;
string msg;
public NetReciever(IPAddress IP)
{
this.tcpListener = new TcpListener(IPAddress.Any, 25565);
this.udpClient = new UdpClient(8080);
UDPThread = new Thread[Main.ConnectionLimit]; //This is set to 1 cuz I can't get this working, so I didn't bother changing it D=
for (int i = 0; i < Main.ConnectionLimit; i++)
{
UDPThread = new Thread(new ThreadStart(UDPListen));
UDPThread.Start();
}
//this.UDPThread = new Thread(new ThreadStart(UDPListen));
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
UDPPacketsCounter = new TimerAction(CountUDPPackets, 1000, false);
//this.UDPThread.Start();
}
public void CountUDPPackets()
{
UDPPacketsCounts = 0;
}
public void Abort()
{
foreach (Thread t in UDPThread)
{
t.Abort();
}
udpClient.Close();
listenThread.Abort();
tcpListener.Stop();
}
public void UDPListen()
{
while (true)
{

IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] receiveBytesUDP = udpClient.Receive(ref RemoteIPEndPoint);
if (receiveBytesUDP != null)
{
UDPPacketsCounts++;
Main.UDPin += receiveBytesUDP.Length / 1000f;
if (Main.isHost)
{
Main.Server.processUDP(Encoding.ASCII.GetString(receiveBytesUDP), RemoteIPEndPoint.Address.ToString());
}
else
{
if (RemoteIPEndPoint.Address.ToString() == Main.HostIP)
{
Program.game.ProcessUDP(Encoding.ASCII.GetString(receiveBytesUDP));
}
}
}
}
}
public void performUDPAsync(IAsyncResult ar)
{

}
public void performTCPAsync()
{

}
public void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient clientTCP = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThreadTCP = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThreadTCP.Start(clientTCP);
}
}
public void HandleClientComm(object client)
{

TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
Socket socket = tcpClient.Client;
byte[] message = new byte[4096];

int bytesRead;
while (true)
{


bytesRead = 0;

try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}

if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}

//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
msg = encoder.GetString(message, 0, bytesRead);
Main.TCPin += message.Length / 1000f;
if (Main.isHost)
{
Main.Server.processTCP(msg, ((IPEndPoint)socket.RemoteEndPoint).Address.ToString());
Console.WriteLine("RMsgTCP: " + msg);
}
else
{
if (((IPEndPoint)socket.RemoteEndPoint).Address.ToString() == Main.HostIP)
{
Program.game.ProcessTCP(msg);
}
}
if (actionToPerformTCP != null)
actionToPerformTCP();
}
tcpClient.Close();
}
}
}


Yes, my game is built upon XNA, but I would be really grateful if someone could
point me to some kind of tutorial or books that could clarify my mistakes...


I recommend the MSDN documentation.

In general, I would use a single UDP socket on each host (client, server).
I would use BeginReceive() to queue a receive operation for a packet, and when that completes, put the packet into a queue, and immediately re-queue another BeginReceive().
In the main loop, I would run on a timer at whatever your step rate is (30 times a second, or whatever), and at each step, empty the entire queue of packets, figure out who the packet came from (include the source IP address as part of the enqueued packet data), and turn it into commands for the simulation.
enum Bool { True, False, FileNotFound };

[quote name='Live0les' timestamp='1315842842' post='4860715']
Yes, my game is built upon XNA, but I would be really grateful if someone could
point me to some kind of tutorial or books that could clarify my mistakes...


I recommend the MSDN documentation.

In general, I would use a single UDP socket on each host (client, server).
I would use BeginReceive() to queue a receive operation for a packet, and when that completes, put the packet into a queue, and immediately re-queue another BeginReceive().
In the main loop, I would run on a timer at whatever your step rate is (30 times a second, or whatever), and at each step, empty the entire queue of packets, figure out who the packet came from (include the source IP address as part of the enqueued packet data), and turn it into commands for the simulation.
[/quote]

Thanks!
I have looked at the msdn documentation, and is http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx
only recieve one message? If I want to queue a recieve operation for a packet, how can i do that? Is there some kind of tutorials or examples?
sorry but i am really new to networking.... thanks!!!!
Do I just create a Queue<string> and whenever the udpClient recieves something set the callback and put it in the queue and wait for another packet using BeginRecieve, then in Server Update() function process each item in the Queue?
I recommend that you profile your server and clients, since you don't really sure the problem has to do anything with the networking at all.

[quote name='hplus0603' timestamp='1315855563' post='4860825']
I would use BeginReceive() to queue a receive operation for a packet, and when that completes, put the packet into a queue, and immediately re-queue another BeginReceive().


If I want to queue a recieve operation for a packet, how can i do that?
[/quote]

I think I already answered that question -- see above!

However, it sounds to me as if networking may be too complex for your current skill level. It sounds as if you're not at the level where you can read reference documentation and make sense of the software libraries they document, and then apply them to the problem you're trying to solve -- currently, it sounds as if you're trying to decode both how software libraries work, and then also how networking works.
enum Bool { True, False, FileNotFound };

[quote name='Live0les' timestamp='1315880044' post='4860938']
[quote name='hplus0603' timestamp='1315855563' post='4860825']
I would use BeginReceive() to queue a receive operation for a packet, and when that completes, put the packet into a queue, and immediately re-queue another BeginReceive().


If I want to queue a recieve operation for a packet, how can i do that?
[/quote]

I think I already answered that question -- see above!

However, it sounds to me as if networking may be too complex for your current skill level. It sounds as if you're not at the level where you can read reference documentation and make sense of the software libraries they document, and then apply them to the problem you're trying to solve -- currently, it sounds as if you're trying to decode both how software libraries work, and then also how networking works.
[/quote]
That's just my case i think...
however, i would like to ask "[color=#1C2837][size=2]I would use BeginReceive() to queue a receive operation for a packet, and when that completes, put the packet into a queue, and immediately re-queue another BeginReceive().", is that means i create a Queue<string> and process it in the server thread, while the BeginRecieve populate the Queue?
I have made that, and still I experience stuttering global voice at my computer, is tat normal or it is only my computer? Thanks!
I am just 13 years old, and I have never touched networking, but I am able to do the local collisions, sync, bullets collision, particle systems and other fundamental parts of my game, I also have a Server class processing my network data, just some switches, it takes the header of the UDP message and process it differently, in the class it also consists of Sending to clients.
the NetUtil class (sending) is as follow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace Project_1001_Forika
{
public class NetUtil
{
public static void SendToHostUDP(string Msg)
{
UdpClient udpClient = new UdpClient();
udpClient.Connect(Main.HostIP, 8080);
byte[] sdBytes = Encoding.ASCII.GetBytes(Msg);
udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient);
Main.UDPout += sdBytes.Length / 1000f;
}
public static void SendToClientUDP(string Msg, IPAddress ip)
{
UdpClient udpClient = new UdpClient();
udpClient.Connect(ip, 8080);
byte[] sdBytes = Encoding.ASCII.GetBytes(Msg);
udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient);
Main.UDPout += sdBytes.Length / 1000f;
}
public static void SendToHostTCP(string Message)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(Main.HostIP), 25565);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
if (clientStream.CanWrite)
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(Message);
clientStream.BeginWrite(buffer, 0, buffer.Length, CallBack, clientStream);
clientStream.Flush();
Main.TCPout += buffer.Length / 1000f;
}
client.Close();
}
public static void CallBack(IAsyncResult ar)
{

}
public static void SendToClientTCP(string Message, IPAddress ip)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(ip, 25565);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
if (clientStream.CanWrite)
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(Message);
clientStream.BeginWrite(buffer, 0, buffer.Length, CallBack, clientStream);
clientStream.Flush();
Main.TCPout += buffer.Length / 1000f;

}
Console.WriteLine("SMsgTCP : " + Message);
client.Close();
}
}
}



At last, thanks for all the comments! Could anyone direct me to a right direction?




public static void SendToHostUDP(string Msg)
{


public static void SendToClientUDP(string Msg, IPAddress ip)
{



You create a new UdpClient each time you send a message. That is not a good idea; it will consume resources, probably break through NAT routers, and may be a reason you're getting the lag you're talking about.

Instead, create a single UdpClient the first time you want to send any data (or, for that matter, accept any data). Assign it to a static member variable of your class. Then send each message through that same UdpClient, passing the address of the target in each time. For receiving, you again want to use a single UdpClient, and the address of who sent the data to you will be delivered as part of the receive operation.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement