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.
Related
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();
}
Multithread programming is a new concept for me. I’ve done a bunch of reading and even with many examples, I just can’t seem to figure it out. I'm new to C# and programming.
I have a winform project with lots of custom controls I’ve imported and will utilize many tcpclients. I’m trying to get each control to be hosted on it’s own separate thread. Right now, I’m trying to get 1 control to behave appropriately with it’s own thread.
I'll show you what I have and then follow up with some questions regarding guidance.
string asyncServerHolder; // gets the server name from a text_changed event
int asyncPortHolder; // gets the port # from a text_changed event
TcpClient wifiClient = new TcpClient();
private void btnStart_Click(object sender, EventArgs e)
{
... // variable initialization, etc.
... // XML setup, http POST setup.
send(postString + XMLString); // Content to send.
}
private void send(string msg)
{
AsyncCallback callBack = new AsyncCallback(ContentDownload);
wifiClient.BeginConnect(asyncServerHolder, asyncPortHolder, callBack, wifiClient);
wifiClient.Client.Send(System.Text.Encoding.ASCII.GetBytes(msg));
}
private void ContentDownload(IAsyncResult result)
{
if (wifiClient.Connected)
{
string response4 = "Connected!!"; //debug msg
byte[] buff = new byte[1024];
int i = wifiClient.Client.Receive(buff);
do
{
response1 = System.Text.Encoding.UTF8.GetString(buff, 0, i);
} while (response1.Length == 0);
response2 = response1.Substring(9, 3); // pick out status code to be displayed after
wifiClient.Client.Dispose();
wifiClient.Close();
}
}
If you're knowledgeable about this, I bet you see lots of problems above. As it stands right now, I always get an exception one my first iteration of running this sequence:
"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied"
Why is this? I have confirmed that my asyncServerHolder and my asyncPortHolder are correct. My second iteration of attempting allowed me to see response4 = "Connected!!" but I get a null response on response1.
Eventually I'd like to substitute in my user controls which I have in a List. I'd just like to gracefully connect, send my msg, receive my response and then allow my form to notify me from that particular control which plays host to that tcp client. My next step would be link up many controls.
Some questions:
1) Do I need more TCP clients? Should they be in a list and be the # of controls I have enabled at that time of btnStart_Click?
2) My controls are on my GUI, does that mean I need to invoke if I'm interacting with them?
3) I see many examples using static methods with this context. Why is this?
Thanks in advance. All criticism is welcome, feel free to be harsh!
BeginConnect returns immediately. Probably, no connection has been established yet when Send runs. Make sure that you use the connection only after having connected.
if (wifiClient.Connected) and what if !Connected? You just do nothing. That's not a valid error recovery strategy. Remove this if entirely.
In your read loop you destroy the previously read contents on each iteration. In fact, you can't split up an UTF8 encoded string at all and decode the parts separately. Read all bytes into some buffer and only when you have received everything, decode the bytes to a string.
wifiClient.Client.Dispose();
wifiClient.Close();
Superstitious dispose pattern. wifiClient.Dispose(); is the canonical way to release everything.
I didn't quite understand what "controls" you are talking about. A socket is not a control. UI controls are single-threaded. Only access them on the UI thread.
Do I need more TCP clients?
You need one for each connection.
Probably, you should use await for all blocking operations. There are wrapper libraries that make the socket APIs usable with await.
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.
Say we want to get API alike this:
var Listner = new ServerSocket();
Listner.Bind(URL);
Listner.OnData((senderClient, ClientDataStream) => {/* ... */})
We also want the delegate passed to OnData be executed in limited multythreaded task pool that does not affect socket receiving performance.
New senderClient tasks shall get into end of task pool only when current task on senderClient was executed.
Ofcourse while working with OnData we shall be capable of writting data back to clients thrue socket.
We can not provide information on next ClientDataStream length when parsing current frame. So ClientDataStream shall provide abilety to read from it as much as needed in form of async operation alike:
{
byte[] data = ClientDataStream.Read(5).Wait();
/* */
byte[] data = ClientDataStream.Read(someDinamicVarNWeGotFromThatFirstFiveBytes).Wait(); //...
}
and while task waits it shall probably allow other tasks to work.
Is there such smart socket server in .Net out of the box or in some OSS library?
I'm not aware of a ServerSocket class in .NET. It's just Socket. It can do stuff asynchronously. There is an extensive article on MSDN: http://msdn.microsoft.com/en-us/library/5w7b7x5f%28v=vs.110%29.aspx
The API is somewhat different from your pseudocode. There is no OnData event, but a BeginReceive method that takes a callback method.
The Socket class does not support async/await out of the box (if you're using .NET 4.5), but I ran into this blog article that defines some extension methods for the class to make it possible to use that programming model as well.
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.