I am making a game which demands great traffic of data like Positions(2D) and many other data.
I am using a very simple class to help me listening on 8080 port(UDP), and a method to send datagram :
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 CallBack(IAsyncResult ar)
{
}
The listener class is just a very simple one:
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);
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()
{
UDPThread.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));
}
}
}
}
So basically when there is 1 player, there will be approximately 60packet/s IN and 60 packets/s out.
It acts like this:
Listen for packets.
Validate the packets.
Process the packets data -> Like storing some of the positions, sending back some packets...
So it just loop like this.
And the problems are here:
Firstly, When there are 2 players(Host+ 1Client), there will be some significant FPS drops at some point, and the host will experience stuttering of all audios(like in blue screen) for a moment.
Secondly, when there are 2+ players(Host + 1+Client), the Host FPS will drop to 5-20, and it will lag+lag+lag+lag but not freezing.
I have read some articles about async, and this is already threaded?
And also BeginRecieve and EndRecieve, I don't really understand how and why do I need to use it.
Could someonekindly provide some examples to explain how to process these kinds of data and send/recieve packets please? I don't really want to use libraries because I want to know what is going on.
P.S: How do the networking system in Terraria works? It uses TCP but it is smooth! How?
PSS: What is buffering? Why do i need to set buffering and how? What does it changes?
PSSS: I think there are something to be tuned and changed in sending the packets, because it just look so simple.
The asyncronous concept is definitely something you want to look into here. What could be the issue is that with everything running on the same thread, certain UI actions (like graphic rendering (your fps loss), or playing sound (your stuttering)) may well be waiting for other aspects of the program, such as network communications.
Normally, you'd seperate the threads out, so that the UI and sound side of things can process on their own, without the dependence on anything else. Have a read of some of the msdn thread examples, then try putting your longer running processes on a seperate thread from your UI and see how that helps:
http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx
If you truly want to create a networked game there will be no way around learning more about network programming than you seem to know so far.
A good start is http://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/. Whilst this is for C++ (I think, but if I remember right someone portet it to C# also, maybe :P) the theory behind all this is explained very well.
It might also be worth reading up on WinAPI socket programming. This will be more technical than reading tutorials on how to do network programming in C#, but it will also make things more clear than using wrappers that obfuscate whats really going on behind the scenes.
Edit:
Basically its up to you weather you use a backgroud thread for listening for packets or use BeginReceive with an AsyncCallback method. The drawback of the latter is that you will eventually need to call EndReceive at which point it will still block you application until the actual receive is finished. Creating your own thread and using blocking mode will obviously not block your UI/business logic (main) thread, but you will need to program the cross thread communication part yourself.
I also found a simple tutorial for an UDP-Client-Server app using threading and blocking mode here.
Related
I'm creating an application with will send and receive vast amount of data via udp packets. I want to have the ability to scale the processing of these requests by adding or diminishing more worker threads. However when I add a second thread and start waiting for data I get the following error.
“Only one usage of each socket address (protocol/network address/port) is normally permitted”
The Code:
static void Main(string[] args)
{
Console.WriteLine("Running...");
Thread threadA = new Thread(new ThreadStart(ProcessMessage));
Thread threadB = new Thread(new ThreadStart(ProcessMessage));
threadA.Start();
threadB.Start();
Console.WriteLine("Press any key.");
Console.ReadLine();
}
private static void ProcessMessage()
{
using (var udpClient = new UdpClient(11000))
{
var sender = new System.Net.IPEndPoint(IPAddress.Any, 11000);
var data = udpClient.Receive(ref sender);
// Do work
}
}
The error is very clear but then my question is: How do I correctly divide the work among multiple threads?
Thanks for the help and sorry for any spelling mistakes.
I'm not a native english speaker.
The comment from C.Gonzalez was very helpful, so I will put it here as the correct answer.
The usual way to handle high volume UDP is to have one thread just consuming data as fast as it can (and putting the content of the messages into a queue). (Any moderately new hardware can receive data as fast as the network can send it) One or more other threads empty and process the data. If a response is necessary, it can be put into an outgoing queue for another dedicated thread to send messages out (you can use the same socket form this dedicated thread). Again, any relatively new hardware can send and receive duplex mode at wire speed with ease.
I'm building a C# Socket Server. My code currently works but I am not sure if this is the correct way to do it.
When a TcpClient is connected I put it in a new object with the following Methods, I then call Init() to start checking if data is available, when data is available I call an event that I listen on to start reading the buffer using methods I created like ReadInt32(), ReadByte(), ReadString() ReadObject<T>()
public void Init()
{
ThreadPool.QueueUserWorkItem(Read);
}
private void Read(object state)
{
if (IsClientConnected())
{
if (_connected.Available > 0)
{
OnDataAvailable(_connected.Available);
}
Init();
}
}
Should I use a While loop here or should I restart the Init() like I am currently doing? Then should I use a BackgroundWorker, Thread, or Task instead of ThreadPool?
I also was thinking of changing Init() to BeginWait(some sort of callback here) and removing the Init() inside the Read() and then just call BeginWait again where needed
My purpose is to listen to commands and reply on commands. With an x number of clients connected at the same time.
So the scenario is as follow:
I have an application that connects to the server.
The server then Initializes a new object with TcpClient as a parameter in the constructor. The server then adds the connected client to a room with another client. This room listens on each of the client's events DataAvailable look at following
private void Client_DataAvailable(ClientWrapper sender, int data)
{
var command = (Commands)Client.ReadByte();
switch (command)
{
case Commands.RequestConnectId: // 1
var buffer = new WriteBuffer(Commands.RequestConnectId);
buffer.WriteInt32(sender.ConnectId);
sender.Reply(buffer);
break;
case Commands.WriteText: //2
var buffer = new WriteBuffer(Commands.WriteText);
buffer.WriteString(sender.ReadString());
BroadCast(sender.ConnectId,buffer);//Send to the other client
break;
}
}
The correct way to read a socket is to just read from it. The call will not complete until data is ready. There is no need for events. The Available property almost always is a bug so don't use that.
Just execute:
var command = (Commands)Client.ReadByte();
immediately. It is fine to run that on a background thread (as opposed to what was suggested in the comments). Threads become a problem once you have too many of them. If you maintain a few dozen socket connections only there is no issue with that.
You also could use async IO preferably with await. The same idea applies: Just read.
If you want to process a stream of command simply wrap this in a loop:
while (true) {
ReadCommand();
WriteResponse();
}
This is to a degree a "basics of TCP" question, yet at the same time I have yet to find a convincing answer elsewhere and believe i have a ok/good understanding of the basics of TCP. I am not sure if the combination of questions (or the one questions and while i'm at it the request for confirmation of a couple of points) is against the rules. Hope not.
I am trying to write a C# implementation of a TCP client, that communicates with an existing app containing a TCP server (I don't have access to its code, so no WCF). How do I connect to it, send and receive as needed as new info comes in or out, and ultimately disconnect. Using the following MSDN code as an example where they list "Send" and "Receive" asynchronous methods (or just TcpClient), and ignoring the connect and disconnect as trivial, how can I best go about continuously checking for new packets received and at the same time send when needed?
I initially used TCPClient and GetStream(), and the msdn code still seems to require the loop and sleep described in a bit (counter intuitively), where I run the receive method in a loop in a separate thread with a sleep(10) milliseconds, and Send in the main (or third) thread as needed. This allows me to send fine, and the receive method effectively polls at regular intervals to find new packets. The received packets are then added to a queue.
Is this really the best solution? Shouldn't there be a DataAvailable event equivalent (or something i'm missing in the msdn code) that allows us to receive when, and only when, there is new data available?
As an afterthought I noticed that the socket could be cut from the other side without the client becoming aware till the next botched send. To clarify then, the client is obliged to send regular keepalives (and receive isn't sufficient, only send) to determine if the socket is still alive. And the frequency of the keepalive determines how soon I will know that link is down. Is that correct? I tried Poll, socket.connected etc only to discover why each just doesn't help.
Lastly, to confirm (i believe not but good to make sure), in the above scenario of sending on demand and receiving if tcpclient.DataAvailable every ten seconds, can there be data loss if sending and receiving at the same time? If at the same time I am receiving I try and send will one fail, overwrite the other or any other such unwanted behaviour?
There's nothing wrong necessarily with grouping questions together, but it does make answering the question more challenging... :)
The MSDN article you linked shows how to do a one-and-done TCP communication, that is, one send and one receive. You'll also notice it uses the Socket class directly where most people, including myself, will suggest using the TcpClient class instead. You can always get the underlying Socket via the Client property should you need to configure a certain socket for example (e.g., SetSocketOption()).
The other aspect about the example to note is that while it uses threads to execute the AsyncCallback delegates for both BeginSend() and BeginReceive(), it is essentially a single-threaded example because of how the ManualResetEvent objects are used. For repeated exchange between a client and server, this is not what you want.
Alright, so you want to use TcpClient. Connecting to the server (e.g., TcpListener) should be straightforward - use Connect() if you want a blocking operation or BeginConnect() if you want a non-blocking operation. Once the connection is establish, use the GetStream() method to get the NetworkStream object to use for reading and writing. Use the Read()/Write() operations for blocking I/O and the BeginRead()/BeginWrite() operations for non-blocking I/O. Note that the BeginRead() and BeginWrite() use the same AsyncCallback mechanism employed by the BeginReceive() and BeginSend() methods of the Socket class.
One of the key things to note at this point is this little blurb in the MSDN documentation for NetworkStream:
Read and write operations can be performed simultaneously on an
instance of the NetworkStream class without the need for
synchronization. As long as there is one unique thread for the write
operations and one unique thread for the read operations, there will
be no cross-interference between read and write threads and no
synchronization is required.
In short, because you plan to read and write from the same TcpClient instance, you'll need two threads for doing this. Using separate threads will ensure that no data is lost while receiving data at the same time someone is trying to send. The way I've approached this in my projects is to create a top-level object, say Client, that wraps the TcpClient and its underlying NetworkStream. This class also creates and manages two Thread objects, passing the NetworkStream object to each during construction. The first thread is the Sender thread. Anyone wanting to send data does so via a public SendData() method on the Client, which routes the data to the Sender for transmission. The second thread is the Receiver thread. This thread publishes all received data to interested parties via a public event exposed by the Client. It looks something like this:
Client.cs
public sealed partial class Client : IDisposable
{
// Called by producers to send data over the socket.
public void SendData(byte[] data)
{
_sender.SendData(data);
}
// Consumers register to receive data.
public event EventHandler<DataReceivedEventArgs> DataReceived;
public Client()
{
_client = new TcpClient(...);
_stream = _client.GetStream();
_receiver = new Receiver(_stream);
_sender = new Sender(_stream);
_receiver.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
Client.Receiver.cs
private sealed partial class Client
{
private sealed class Receiver
{
internal event EventHandler<DataReceivedEventArgs> DataReceived;
internal Receiver(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for receiving data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Client.Sender.cs
private sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
// transition the data to the thread and send it...
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for sending data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Notice that these are three separate .cs files but define different aspects of the same Client class. I use the Visual Studio trick described here to nest the respective Receiver and Sender files under the Client file. In a nutshell, that's the way I do it.
Regarding the NetworkStream.DataAvailable/Thread.Sleep() question. I would agree that an event would be nice, but you can effectively achieve this by using the Read() method in combination with an infinite ReadTimeout. This will have no adverse impact on the rest of your application (e.g., UI) since it's running in its own thread. However, this complicates shutting down the thread (e.g., when the application closes), so you'd probably want to use something more reasonable, say 10 milliseconds. But then you're back to polling, which is what we're trying to avoid in the first place. Here's how I do it, with comments for explanation:
private sealed class Receiver
{
private void Run()
{
try
{
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutdownEvent.WaitOne(0))
{
try
{
// We could use the ReadTimeout property and let Read()
// block. However, if no data is received prior to the
// timeout period expiring, an IOException occurs.
// While this can be handled, it leads to problems when
// debugging if we are wanting to break when exceptions
// are thrown (unless we explicitly ignore IOException,
// which I always forget to do).
if (!_stream.DataAvailable)
{
// Give up the remaining time slice.
Thread.Sleep(1);
}
else if (_stream.Read(_data, 0, _data.Length) > 0)
{
// Raise the DataReceived event w/ data...
}
else
{
// The connection has closed gracefully, so stop the
// thread.
ShutdownEvent.Set();
}
}
catch (IOException ex)
{
// Handle the exception...
}
}
}
catch (Exception ex)
{
// Handle the exception...
}
finally
{
_stream.Close();
}
}
}
As far as 'keepalives' are concerned, there is unfortunately not a way around the problem of knowing when the other side has exited the connection silently except to try sending some data. In my case, since I control both the sending and receiving sides, I've added a tiny KeepAlive message (8 bytes) to my protocol. This is sent every five seconds from both sides of the TCP connection unless other data is already being sent.
I think I've addressed all the facets that you touched on. I hope you find this helpful.
I have run into an issue with the slow C# start-up time causing UDP packets to drop initially. Below, I is what I have done to mitigate this start-up delay. I essentially wait an additional 10ms between the first two packet transmissions. This fixes the initial drops at least on my machine. My concern is that a slower machine may need a longer delay than this.
private void FlushPacketsToNetwork()
{
MemoryStream packetStream = new MemoryStream();
while (packetQ.Count != 0)
{
byte[] packetBytes = packetQ.Dequeue().ToArray();
packetStream.Write(packetBytes, 0, packetBytes.Length);
}
byte[] txArray = packetStream.ToArray();
udpSocket.Send(txArray);
txCount++;
ExecuteStartupDelay();
}
// socket takes too long to transmit unless I give it some time to "warm up"
private void ExecuteStartupDelay()
{
if (txCount < 3)
{
timer.SpinWait(10e-3);
}
}
So, I am wondering is there a better approach to let C# fully load all of its dependencies? I really don't mind if it takes several seconds to completely load; I just do not want to do any high bandwidth transmissions until C# is ready for full speed.
Additional relevant details
This is a console application, the network transmission is run from a separate thread, and the main thread just waits for a key press to terminate the network transmitter.
In the Program.Main method I have tried to get the most performance from my application by using the highest priorities reasonable:
public static void Main(string[] args)
{
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
...
Thread workerThread = new Thread(new ThreadStart(worker.Run));
workerThread.Priority = ThreadPriority.Highest;
workerThread.Start();
...
Console.WriteLine("Press any key to stop the stream...");
WaitForKeyPress();
worker.RequestStop = true;
workerThread.Join();
Also, the socket settings I am currently using are shown below:
udpSocket = new Socket(targetEndPoint.Address.AddressFamily,
SocketType.Dgram,
ProtocolType.Udp);
udpSocket.Ttl = ttl;
udpSocket.SendBufferSize = 1024 * 1024;
udpSocket.Blocking = true;
udpSocket.Connect(targetEndPoint);
The default SendBufferSize is 8192, so I went ahead and moved it up to a megabyte, but this setting did not seem to have any affect on the dropped packets at the beginning.
From the comments I learned that TCP is not an option for you (because of inherent delays in transmission), also you do not want to loose packets due to other side being not fully loaded.
So you actually need to implement some features present in TCP (retransmission) but in more robust and lightweight fashion. I also assume that you are in control of the receiving side.
I propose that you send some predetermined number of packets. And then wait for confirmation. For instance, every packet can have an id that constantly grows. Every N packets, receiving application sends the number of last received packet to the sender. After receiving this number sender will know if it is necessary to repeat last N packets.
This approach should not hurt your bandwidth very much and you will get some sort of information about received data (although not guaranteed).
Otherwise it is best to switch to TCP. By the way did you try using TCP? How much your bandwidth hurts because of it?
I'm pretty new to serialization so please bear with me.
I want two instances of my application to communicate with each other over the internet. I have successfully rigged up a TCP client/server relationship and used a binary formatter to get the two sides to swap a single pair of messages. Here's the client side...
using (TcpClient clientSocket = new TcpClient(ipAddress, currentPort))
{
using (NetworkStream stream = clientSocket.GetStream())
{
// send
bformatter.Serialize(stream, new Message());
// recv
return (Message)bformatter.Deserialize(stream);
}
}
It's cool, but not very useful for an application that needs to send messages in response to user events. So I need to be able to send and receive asynchronously.
I basically want an interface that behaves like this:
class BidirectionalObjectStream
{
public BidirectionalObjectStream(TcpClient client)
{
//...
}
// objects go in here
public void SendObject(object o)
{
//...
}
// objects come out here
public event Action<object> ObjectReceived;
}
Is there a class like this that's part of .NET? If not, how should I implement the receive event? Maybe a dedicated thread calling bformatter.Deserialize() repeatedly...?
Any help appreciated.
The question is a little broad.
I can think of two options:
Use asynchronous socket. Using an Asynchronous Client Socket
Create separate threads for receiving and sending. There many ways to achieve it, raw Thread, ThreadPool, delegate.Invoke, new TPL features like Task and Parallel.