Working on client server using sockets and tcp\ip in C# - c#

I am working on client-server data receiving. I am able to receive data from the server which is my meter. The code is below
listner = new TcpListener(new IPEndPoint(IPAddress.Any, port));
Console.WriteLine("Listening...");
listner.Start();
while (true)
{
try
{
//---incoming client connected---
TcpClient client = listner.AcceptTcpClient();
//---get the incoming data through a network stream---
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
//---read incoming stream---
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//---convert the data received into a string---
string dataReceived = BitConverter.ToString(buffer, 0, bytesRead);
//Encoding.ASCII.GetString(buffer, 0, bytesRead);
//Console.WriteLine("Received : " + dataReceived);
//MessageBox.Show("Data Received", dataReceived);
//---write back the text to the client---
//Console.WriteLine("Sending back : " + dataReceived);
//nwStream.Write(buffer, 0, bytesRead);
client.Close();
}
catch (Exception ex)
{
}
Using the above code I am able to receive the data. But I want to perform the following
Keeping listening on the port
While listening I want to send some bytes to the server (meter)
Get a response from the server after sending some data.
I know there are lots of client-server tutorials but they have a separate implementation of server and client. I just want to handle the client(my software). I have also tried with Asynchronous Server Socket Example.
Any help would be highly appreciated.

Your server needs to continually listen for connections from clients. Each time it gets a connection you get from the OS a new TcpClient to handle that connection. the TcpClient that you get from the OS is sometimes called a Child TcpClient because it's created by the listening port. But it's functionally the same as any other socket.
This is very easy to achieve with the async/await pattern.
First you need a listener that waits for connections, everytime it gets a connection it passes this off to another task that processes the child TcpClient. e.g.,
static async Task StartTcpServerAsync()
{
var tcpListener = new TcpListener(new IPEndPoint(IPAddress.Any, 9999));
tcpListener.Start();
while (true)
{
var tcpClient = await tcpListener.AcceptTcpClientAsync();
// Fire and forget the Child connection
_ = StartChildTcpClientAsync(tcpClient);
}
}
In the above boiler plate code we're completely forgetting about the ChildTcpClient task. You might or might not want this. If you make the task completely self sufficient (as this demo is) then the main task may never need to know if it finished or not. But if you need to be able to provide feedback between the ChildTcpClient Task and the main task then you'll need to provide some additional code to manage this and you'd start by storing the Task returned from StartChildTcpClientAsync(tcpClient); somewhere so you can observe it. You could use Task.Run() here, but it is not necessary in a Console application.
Now that you've got your listener Task, you need a ChildTcpClient Task, eg:
static async Task StartChildTcpClientAsync(TcpClient tcpClient)
{
Console.WriteLine($"Connection received from: {tcpClient.Client.RemoteEndPoint.ToString()}");
using var stream = tcpClient.GetStream();
var buffer = new byte[1024];
while (true)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
await stream.WriteAsync(buffer, 0, bytesRead);
}
}
That's a super simple Tcp echo client. It's got no flow control and no error handling the task will just sit there forever waiting for the client to send some data even after the client has disconnected. This Task just "awaits" for infinity (or until an exception occurs) so you need to add some code in here to manage the client, check that the client is still connected, etc etc
To pull it all together you simply need a main like this:
static async Task Main(string[] args)
{
await StartTcpServerAsync();
// Will never exit unless tcpListener.AcceptTcpClientAsync();
// throws an exception
}
And that's it, you have a Console Application that waits for an infinite number of clients to connect, and each time one does it has it's own Task to deal with the IO.

Related

How to close the TcpClient with a timeout?

I'm using .NET Core and want to send messages via TCP. For this I'm using the TcpClient class and created a custom service. This solution works for now, not sure if I can improve it
class MyTcpService : IMyTcpService
{
private readonly TcpClient tcpClient = new TcpClient();
public async Task Send(byte[] bytesToSend)
{
if (!tcpClient.Connected) // Check if client was closed before
{
await tcpClient.ConnectAsync("127.0.0.1", 5000); // Read values from config
}
NetworkStream networkStream = tcpClient.GetStream();
// Send the message
await networkStream.WriteAsync(bytesToSend, 0, bytesToSend.Length);
// Read the response
byte[] responseBuffer = new byte[1024]; // Read value from config
int amountOfResponseBytes = await networkStream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
string responseMessage = Encoding.ASCII.GetString(responseBuffer, 0, amountOfResponseBytes);
// Close the connection with a timeout if true
if (true) // Read value from config
{
networkStream.Close(1000); // Read value from config
tcpClient.Close();
}
// Handle the response message here
// ...
}
}
I want to inject IMyTcpService as a transient service. I would like to know how to close the client with a timeout? The Socket class has a Close method accepting a timeout parameter
https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.close?view=netcore-3.1#System_Net_Sockets_Socket_Close_System_Int32_
but I'm not able to find an equivalent for the TcpClient just for its NetworkStream.
At the moment you are awaiting both the WriteAsync and ReadAsync calls. Because of this the timeout in your call to networkStream.Close(1000) should have no impact and the connection will always close immediately as no data is waiting to be sent/received. For neither the write or read you have specified a timeout, which means they won't return until data has finished being transferred.
I would like to know how to close the client with a timeout?
It's not clear why you want this or what you want to achieve with this. TcpClient is simply a wrapper around a NetworkStream which in turn wraps around a Socket. So handling timeouts both on the TcpClient and the NetworkStream doesn't make much sense.
Resource management:
In your current example I would first of all advise you to keep the TcpClient inside the Send method instead of a class field. If you don't need to use the TcpClient in other places (which expect you don't since you are closing it in the Send function) you should narrow it's scope for easier resource management. While doing that I'd suggest you make use of the using statement to avoid forgetting to properly dispose your resources. This applies to all types that implement the IDisposable interface (of course there are exceptions to this).
Handling timeout:
To handle timeouts in this snippet of code you have shared I suggest you configure the timeout on the write and read operations rather than the close operation, since your code is very sequential. An example of what that could look like:
class MyTcpService : IMyTcpService
{
public async Task Send(byte[] bytesToSend)
{
string responseMessage;
using (tcpClient = new TcpClient())
{
if (shouldUseTimeout) // From config
{
tcpClient.ReceiveTimeout = 1000; // From config
tcpClient.SendTimeout = 1000; // From config
}
await tcpClient.ConnectAsync("127.0.0.1", 5000); // Read values from config
NetworkStream networkStream = tcpClient.GetStream();
// Send the message
await networkStream.WriteAsync(bytesToSend, 0, bytesToSend.Length);
// Read the response
byte[] responseBuffer = new byte[1024]; // Read value from config
int amountOfResponseBytes = await networkStream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
responseMessage = Encoding.ASCII.GetString(responseBuffer, 0, amountOfResponseBytes);
}
// The tcpClient is now properly closed and disposed of
// Handle the response message here
// responseMessage...
}
}
Update in response to the comment 13/10/2020:
hey, thanks for your reply :) I tried to improve your answer, what do you think about this snippet? pastebin.com/7kTvtTv2
From your https://pastebin.com/7kTvtTv2:
public async Task<string> Send(byte[] messageToSend)
{
string responseMessage;
using (TcpClient tcpClient = new TcpClient())
{
await tcpClient.ConnectAsync("127.0.0.1", 5000); // From config
NetworkStream networkStream = tcpClient.GetStream();
await networkStream.WriteAsync(messageToSend, 0, messageToSend.Length);
await networkStream.FlushAsync();
tcpClient.Client.Shutdown(SocketShutdown.Send); // shutdown gracefully
byte[] responseBuffer = new byte[256]; // This can be of any size
StringBuilder stringBuilder = new StringBuilder();
int amountOfResponseBytes;
do
{
amountOfResponseBytes = await networkStream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
string responseData = Encoding.ASCII.GetString(responseBuffer, 0, amountOfResponseBytes);
stringBuilder.Append(responseData);
} while (amountOfResponseBytes > 0);
responseMessage = stringBuilder.ToString();
}
return responseMessage;
}
Looks pretty good to me. Only some minor comments:
await networkStream.FlushAsync() - it seems like this should be unnecessary when I look at the remarks for the Flush method but I haven't tested it:
The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no effect on network streams. Calling the Flush method does not throw an exception
tcpClient.Client.Shutdown(SocketShutdown.Send) - this method simply tells the Socket to no longer allow writing/sending data. Since your TcpClient only stays within the Send method and therefore not being shared anywhere it seems a little unnecessary too. I think the Shutdown method is mostly relevant if you don't have complete control over when the Socket is used.
do { ... } while (...) - looks good to me. Just remember the responseBuffer need to be a multiple of 8 if you are dealing with ASCII characters so you don't end up trying to decode a partial character.
Where did the timeout handling go? Did you forget to add timeout handling or is it not relevant anymore? Currently, if you have a lot of data to send or receive or the network is just slow, the WriteAsync and ReadAsync calls may potentially take a long time.

Socket Constant Streaming Data

I have a server application but am getting some intermittent timeouts. I want to start writing back to the client immediately and then defer the rest of my write until my payload is ready. However, nothing I've seen in TcpClient or NetworkStream supports active streaming. In my own test bed, any write to the stream is in isolation, even the Begin/End methods.
For example, in my client side write/read loop, the following server code only sends back a single time entry instead of two.
static void Main(string[] args)
{
var listener = TcpListener.Create(2345);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClientAsync().Result;
ThreadPool.QueueUserWorkItem(async state =>
{
try
{
await HandleClient(state);
}
catch (SocketException error) when (error.Message.Contains("existing connection was forcibly closed"))
{
// do nothing
}
}, client);
}
}
private static async Task HandleClient(object state)
{
var client = (TcpClient) state;
var stream = client.GetStream();
while (true)
{
var readBuffer = new byte[4096];
var requestSize = await stream.ReadAsync(readBuffer, 0, readBuffer.Length);
var requestString = Encoding.ASCII.GetString(readBuffer, 0, requestSize);
Console.WriteLine($"[{DateTime.Now.ToLongTimeString()}] Received: {requestString}");
if (requestString == "quit")
{
break;
}
var responseString = DateTime.Now.ToLongTimeString();
var writeBuffer = Encoding.ASCII.GetBytes(responseString);
stream.BeginWrite(writeBuffer, 0, writeBuffer.Length, DelayedWriteCallback, stream);
}
client.Close();
client.Dispose();
}
private static void DelayedWriteCallback(IAsyncResult ar)
{
var stream = (NetworkStream) ar.AsyncState;
Thread.Sleep(5000);
var writeString = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
stream.Write(writeString, 0, writeString.Length);
stream.Flush();
stream.EndWrite(ar);
}
How do I do this?
TCP is a streaming protocol, which just means that it will transport any data you send through it and make sure it is received in the correct order on the other side.
That data might be a constant series of bytes, or many seconds of nothing followed by a single byte. TCP does not care, it´s just the pipe for.
This is made clear by the fact that every socket Send and Receive method takes a buffer with a specific size as a parameter (same goes for NetworkStream). The "streaming" of useful data is up to the application, as is the reception and interpretation of the data.
If you want to send data continuously, you need a send() loop that will pump bytes into the socket as soon as your server has them. If you need to read data continuously, you need a loop that will receive() chunks of bytes continuously and make sense of them.

New thread for every TcpCLient - or what is way to get 100+ clients

I write WPF application. What is app do its - Just listen data from gps tracker.
Problem is - I dont know how handle 100+ devices. I mean - now I do like:
{
var serviceIP = System.Configuration.ConfigurationManager.AppSettings.Get("sericeIP");
var servicePort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings.Get("sericePort"));
var dispatcher = Dispatcher.CurrentDispatcher;
IPAddress localAddr = IPAddress.Parse(serviceIP);
_client = new TcpListener(localAddr, servicePort);
_client.Start();
new Thread(() =>
{
while (true)
{
TcpClient tcpClient = _client.AcceptTcpClient();
new Thread(() => AcceptClient(tcpClient, dispatcher)).Start();
}
});
}
private void AcceptClient(TcpClient client, Dispatcher dispatcher)
{
client.ReceiveTimeout = 13000;
while (client.Connected)
{
try
{
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
// My logic
}
catch (Exception ex)
{ }
}
}
For 1 device its OK - but now I think what will be with 100 - 500-1000 devices.........1000 thread will kill machine - so I dont know what way is better for listen big count of devices
You need to use asynchronous programming. There are several articles that will help you do that. MSDN got an example for instance. With async, you do not need to allocate threads yourself. .NET takes care of that. And all threads are freed when the OS is waiting on IO operations. Thus a much smaller number of threads can handle your connections.
If you are going to receive data from 1000 devices, why are you doing it in a client application? What should the devices do when the WPF application is closed?
It's much better to receive the information in a windows service and store the information in a database. In that way you can also go back and to analysis on all received information.

c# tcp socket receive loop break logic

I'm writng a c# tcp socket server which will receive data from c++ socket application. Now everything works good except the loop break logic inside my c# receiving thread. I'm showing a code snippet below to explain better.
//creating socket object
private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//accepting connections
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
this.socket = tcpListener.AcceptSocket();
tcpListener.Stop();
//code for
//public byte[] ReceiveMessage(ref int intError)
while (this.socket.Available > 0)
{
try
{
intBytesReceived = this.socket.Receive(byteReceivedBuffer, byteReceivedBuffer.Length, SocketFlags.None);
Thread.Sleep(100);
}
catch (SocketException ex)
{
string str = ex.Message;
intError = -1;
}
}
Below is the thread function to receive data continuously
//Thread to continuous poll data from client
//Now this has been done as I need to receive multiple messages from client after server ack received at client side.
//Thread quit logic based on manual stop button press
//I want to have one more logic by which thread will exit if the connection closed by client socket. i.e. a call of 'CloseSocket()' function from c++ application.
if (TCPServerListener.serverStatus == TCPServerListener.ServerStatus.Stopped)
{
tcpCommunication.Disconnect();
break;
}
while(true)
{
int sockError = 0;
byte[] byteData = tcpCommunication.ReceiveMessage(ref sockError);
if (byteData.Length > 0)
{
ParseBuffer(byteData, ref tcpCommunication);
}
}
For better picture I'm wrting below my communication protocol.
Client initiate a connection. Send a data set
Server receives, process, send ack
Client is in halt mode until it receive the ack from server, but didn't close the socket
This time, server will not receive any message but the receiving thread should active as I'm creating a single thread for each client.
Once the client receives the ack it will continue to send next data
Server receiving thread will get data now and process accordingly
Once client closes down its socket, server receiver thread should close also
I'm able to getting my work done but the server receiver thread is not getting closed. That's my problem. Any suggestions would be a off great help.
It has been my experience that when you use a TCP server/client socket relationship, the TCP server socket side will be in a thread that is controlled by a flag to continue listening until told to stop (Your comments mention a stop button).
The client side runs until all data is done, or the same flag controlling the server side is tripped.
When a client connects, I would store the AcceptSocket into a list. When I did this, I had a custom class that the takes the AcceptSocket and the custom class had counters for like how many messages, or bytes was sent/received to/from this client.
// This should be a threaded method if you're using a button to stop
private void StartTcpListener()
{
List<ClientClass> clientClassList = new List<ClientClass>();
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
while (keepListening)
{
Socket socket = tcpListener.AcceptSocket();
// Create a client object and store it in a list
ClientClass clientClass = new ClientClass(socket);
clientClassList.Add(clientClass);
// This method would start a thread to read data from the accept socket while it was connected.
clientClass.Start();
}
foreach (ClientClass client in clientClassList)
{
// This method would stop the thread that reads data from the accept socket and close the accept socket
client.Stop();
}
tcpListener.Stop();
}
For the client side, when reading from the client accept socket this would be thread controlled and either the thread is aborted or the client closes its end causing the read to return a -1 for number of bytes read.
// Threaded method
private void Receive()
{
// Don't know how much of a buffer you need
byte[] dataIn = byte[1000];
while (acceptSocket.Connected)
{
// Exception handling so you either end the thread or keep processing data
try
{
int bytesRead = acceptSocket.Read(dataIn);
if (bytesRead != -1)
{
// Process your data
}
else
{
// -1 Bytes read should indicate the client shutdown on their end
break;
}
}
catch(SocketException se)
{
// You could exit this loop depending on the SocketException
}
catch(ThreadAbortException tae)
{
// Exit the loop
}
catch (Exception e)
{
// Handle exception, but keep reading for data
}
}
// You have to check in case the socket was disposed or was never successfully created
if (acceptSocket != null)
{
acceptSocket.Close();
}
}
// This is the stop method if you press your stop button
private void Stop()
{
// Aborts your read thread and the socket should be closed in the read thread. The read thread should have a ThreadState.Stopped if the while loop was gracefully ended and the socket has already been closed
if (readThread != null && readThread.ThreadState != ThreadState.Stopped)
{
readThread.Abort();
}
}
I think this is the basics of what I've done before. I'm sure there are "cleaner" ways of doing this now. This was years ago when I use to implement TCP client/server socket objects.
Hope this helps...

Send data from a background thread to the main thread

I am running a C# server from the main application and I would like to pass the message received from the server thread to the main thread. The server should be running on the background for new connections. Every time there is a new connection the server should pass the message received to the main app. How can let the main app know when the message is received? and how can pass the message from the server thread to the main when there is a new connection?
Main application
public partial class MainWindow : Window
{
TCPServer Server = new TCPServer(); //start running the server
//get the message (Server.message) when a client sent it to the server
//TODO process the message
}
TCP server
class TCPServer
{
private TcpListener tcpListener;
private Thread listenThread;
private String message;
public TCPServer()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3200);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
//starts the tcp listener and accept connections
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
System.Diagnostics.Debug.WriteLine("Listening...");
TcpClient client = this.tcpListener.AcceptTcpClient();
System.Diagnostics.Debug.WriteLine("Client connected");
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
//Read the data from the client
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client; //start the client
NetworkStream clientStream = tcpClient.GetStream(); //get the stream of data for network access
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) //if we receive 0 bytes
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
message = encoder.GetString(message, 0, bytesRead);
//Reply
byte[] buffer = encoder.GetBytes("ACK");
clientStream.Write(buffer, 0, buffer.Length);
System.Diagnostics.Debug.WriteLine("ACK");
clientStream.Flush();
}
tcpClient.Close();
System.Diagnostics.Debug.WriteLine("Client disconnected");
}
This is already well supported by TcpListener, use the BeginAcceptTcpClient() method instead. When you call it from the main thread of a WPF or Winforms app then the callback will run on the same main thread automatically. The same applies to its BeginReceive() method. Internally it uses the dispatcher loop to get the callback method activated, pretty similar to the way a class like BackgroundWorker and the C# v5 async/await keywords work.
This saves you from the hassle of starting end terminating your own thread and ensuring you marshal back properly. And significantly cutting down on the resource usage of your program. Highly recommended.
A Queue is the answer. Specifically in this case a Concurrent Queue.
Your socket thread puts messages into the queue. Your worker thread(s) poll the queue and pulls work items out.
For socket based applications, this pattern is very, very common.
Alternatively, you can QueueUserWorkItem against the system thread pool, and let it manage the work load.
Note: You're in multi-threaded land now. You'll need to read about synchronization and other issues that are going to arise. Failure to do this means your app will have very weird bugs.

Categories