c# tcp socket receive loop break logic - c#

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...

Related

Working on client server using sockets and tcp\ip in 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.

My UI lags while trying to connect to a socket?

When I try to connect to my server socket, my interface lags, and the catch doesn't run.
Here's my code :
protected void OnButtonClicked(object sender, EventArgs args)
{
if (!clientSocket.Connected)
{
try
{
clientSocket.Connect("172.20.10.4", 100);
}
catch (SocketException)
{
gettext.Text = "Couldn't Connect";
}
}
SendLoop();
}
private void SendLoop()
{
gettext.Text = "get ivi type";
string req = gettext.Text;
byte[] buffer = Encoding.ASCII.GetBytes(req);
clientSocket.Send(buffer);
byte[] BuffRec = new byte[1024];
int rec = clientSocket.Receive(BuffRec);
byte[] data = new byte[rec];
Array.Copy(BuffRec, data, rec);
gettext.Text = Encoding.ASCII.GetString(data);
}
As a result I'd like to display the exception message when I'm not connected to the socket.
Simplistically, you need to do all this asyncronously. Your UI freezes (not lags - lagging implies it's going slowly but it is moving, it's just some time behind) because the thread that would ordinarily be busy drawing the UI and keeping it responding, is waiting on the connection to connect, then it's sending and receiving data
Where you've said Connect, Send and Receive, those need to be ConnectAsync, SendAsync and ReceiveAsync. You'll need to make other code changes to use async methods, such as marking your own methods as async and using the await keyword before method calls that could block.
By switching to using xAsync methods, when your UI is going to get blocked up waiting for a connection to complete, or for data to transfer, the code will pause what it's doing and go back to drawing the UI. When data is available etc, it will be called back to the point where it left off, and carry on processing
I also recommend you don't try to call SendLoop outside of your check whether the socket is connected..

ManualResetEvent stopping socket program in windows service after sometime

I have a windows service which is monitoring a Socket using TCP/IP protocol.As per my requirement my code is establishing a connection to the Machine and receiving data from there and this i want continuously,that's why i have made it in windows service.But the problem that i am facing is that, the service is reading socket ports for 3-4 hours after that automatically stops reading from the port whereas my service status from Services.msc shows its running.
Here is my code for windows Service..
string ipaddress, textfileSaveLocation;
Byte[] bBuf;
string buf;
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private System.Threading.Thread _thread;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
string df = "";
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
_thread = new Thread(DoWork);
_thread.Start();
}
private void DoWork()
{
// create and monitor socket here...
ipaddress = "192.168.1.100";
int port = int.Parse("8181");
byte[] data = new byte[1024];
string stringData;
string input;
IPAddress ipadd = IPAddress.Parse(ipaddress);
IPEndPoint ipend = new IPEndPoint(ipadd, port);
sock.NoDelay = false;
try
{
sock.Connect(ipend);
}
catch (Exception dfg)
{
return;
}
try
{
input = "Client here";
sock.Send(Encoding.ASCII.GetBytes(input));
while (!_shutdownEvent.WaitOne(0))
{
data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
}
}
catch (Exception DFGFD)
{
}
}
protected override void OnStop()
{
sock.Shutdown(SocketShutdown.Both);
sock.Close();
_shutdownEvent.Set();
_thread.Join(); // wait for thread to stop
}
}
}
Why is my service stopping receiving data after 3-4 hours ?Please help me to resolve this.
Here is my code to insert ServerMachine data into text file..
try
{
FileStream fs = new FileStream(textfileSaveLocation, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite);
StreamWriter swr = new StreamWriter(textfileSaveLocation,true);
swr.WriteLine(stringData);
swr.Close();
swr.Dispose();
fs.Close();
fs.Dispose();
}
catch (Exception Ex)
{
}
As #nobugz has pointed out, you have two problems.
First, you're swallowing any exceptions that occur in DoWork(). You're catching them, yes, but you're not reporting them. Why does it stop after a few hours? Well, the server might have closed, which would terminate your socket connection. You're not attempting to reconnect, so the thread exits, but the process continues to run. Put some exception reporting in to see why the socket is closing and then handle it accordingly.
And this leads to the second point, namely you have no recovery capability. Once an exception occurs or the socket is gracefully closed for some reason, your thread exits. If you want this to work continually, then you'll need to add logic that attempts to reconnect in the cases where something goes wrong. In other words, the only reason that DoWork() exits is due to a shutdown event. Otherwise, it will need to loop, attempting to reconnect when errors occur. As #nobugz said, this will also require you to reset the ManualResetEvent so that your receive loop will work as expected when a reconnect occurs. However, you do not need to call Reset() in the OnStart() callback because you've initialized _shutdownEvent to false, which is what Reset() does.
HTH.
EDIT:
This is off the cuff, so I won't verify its accuracy. I'll fix any problem you (or others) may find.
Define a ManualResetEvent object for shutdown notification. Change the OnStart() callback to this:
using System.Threading;
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
Thread _thread;
protected override void OnStart(string[] args)
{
// Create the thread and start it.
_thread = new Thread(DoWork);
_thread.Start();
}
Since you're wanting a TCP connection, I would strongly recommend using TcpClient as opposed to Socket. Change your DoWork() callback to something like this:
using System.Net.Sockets;
private void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
TcpClient client = new TcpClient();
try
{
// This is a blocking call. You might want to consider one of the
// asynchronous methods...
client.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.100"), 8181));
}
catch (Exception ex)
{
// Log the error here.
client.Close();
continue;
}
try
{
using (NetworkStream stream = client.GetStream())
{
byte[] notify = Encoding.ASCII.GetBytes("Client here");
stream.Write(notify, 0, notify.Length);
byte[] data = new byte[1024];
while (!_shutdownEvent.WaitOne(0))
{
int numBytesRead = stream.Read(data, 0, data.Length);
if (numBytesRead > 0)
{
string msg = Encoding.ASCII.GetString(data, 0, numBytesRead);
}
}
}
}
catch (Exception ex)
{
// Log the error here.
client.Close();
}
}
}
Finally, in the OnStop() callback, trigger the thread to shutdown:
protected override void OnStop()
{
_shutdownEvent.Set(); // trigger the thread to stop
_thread.Join(); // wait for thread to stop
}
Now, it is very important to understand that TCP communication is stream-based. What this means is that you are not guaranteed to receive a complete message each time you do a read of the socket (e.g., TcpClient). If the server sends back the message "Client notification received", reading the socket initially might only get "Client noti". A subsequent read might get "fication recei". A third read might get "ved". It's up to you to buffer the reads together and then process the message. Most protocols will use some kind of header that indicates the type and length of the message. If you're simply using strings, the type of message won't matter since everything's a string. Further, knowing where the string ends could be done using a null terminator instead of prepending the length for example. Just know that reading a TCP socket may only get a portion of the message you're expecting to receive.

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.

Changing TCPClient port dynamically

Lets say you having the following code.
this._tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
clientThread.Start(client);
}
private void HandleClientCommunication(object client)
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Do my work
}
}
The problem with such an implementation is that whatever port I have used in the initial connection is then used in the client communication and therefor (despite the fact that the tcpListener is still listening it will be unable to accept other connections till the port is freed).
So is there someway to tell the tcpClient to change the port it is working on or is the only way to implement such functionality by sending back the client a new port number and telling it to reconnect?
IE:
TcpListener1.AcceptTcpClient(); //Wait
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
clientThread.Start(client);
private void HandleClientCommunication(object client)
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Generate random port number send back to client and create another thread with a new tcpListener and wait again?
}
}
Looking at the code it appears that
the localendpoint for the client and
the remoteendpoint for the server
appears to change to a different port
yet the inverse in each case stays the
same.
IE:
Started server tcpListener on 121
ClientLocalEndPoint: {127.0.0.1:1380}
ClientRemoteEndPoint: {127.0.0.1:121}
ServerLocalEndPoint: {127.0.0.1:121}
ServerRemoteEndPoint: {127.0.0.1:1380}
You are incorrect about the problem here; Spawning a new thread to handle the TcpClient and then looping back to TcpListener.AcceptTcpClient() does not require you to change ports; A single server can get multiple connections in to the same socket.
Otherwise, how would web servers handle multiple users at once?
Something else is going wrong with your code somewhere. Your "thread-per-connection" code is not ideal (a thread per connection is much more than is needed), but it is a quick-and-dirty way that works just fine.
How are you constructing the Listener? What are you doing with the client? And what exactly is happening to subsequent connections?
I agree with others that you might want to look at asynchronous methods instead of using separate threads for each connection, or at least BackgroundWorker... As for what is happening, did you try debugging making sure that you had one thread stuck on the AcceptTcpClient call? You could try specifying a high backlog in your Start() call. Could it be something with scope and maybe garbage collection of your thread because you don't maintain a reference for it? If you put a Thread.Sleep(10000) at the end of your loop, can you connect after 10 seconds? If you try using command line telnet to connect to the port (i.e. "telnet localhost 9999") does the screen blank showing that it connected?
You could try something like adding a hashtable to store your threads and remove them on exit which adds the benefit of having a list of them and being able to close the connections and kill them...
Dictionary<TcpClient, Thread> _threads = new Dictionary<TcpClient, Thread>();
object _lockObject = new object();
void AddThread(TcpClient client, Thread thread)
{
lock (_lockObject)
{
_threads.Add(client, thread);
}
}
void RemoveThread(TcpClient client)
{
lock (_lockObject)
{
_threads.Remove(client);
}
}
void YourMainMethod()
{
this._tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
AddThread(client, clientThread);
clientThread.Start(client);
}
}
private void HandleClientCommunication(object client)
{
try
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Do my work
}
} catch (Exception)
{
// so program doesn't crash
}
finally
{
RemoveThread((TcpClient)client);
}
}

Categories