I have a modified asynchronous socket listener running based on Microsoft's example:
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example
So it's always running and listening for incoming data.
I'm running it from the winform like this:
Task.Run(() => { AsynchronousSocketListener asl = new AsynchronousSocketListener(); });
I have a label on my form called LastMessage, once some data has been received on the socket I want to:
1. Make it visible
2. Change the text of the label to a value I extracted from incoming data from the socket listener.
I've searched around and tried to implement multiple solutions but couldn't get it working and I feel like I'm missing or misunderstanding something, what code needs to run on the form, what needs to run in the task, and most importantly, the server always has to stay up to listen for more incoming data, since all the solutions I saw are waiting for the task to end or return some value.
Thanks in advance.
Related
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.
I am creating a Windows service in C#. Its purpose is to consume info from a feed on the Internet. I get the data by using zeromq's pub/sub architecture (my service is a subscriber only). To debug the service I "host" it in a WPF control panel. This allows me to start, run, and stop the service without having to install it. The problem I am seeing is that when I call my stop method it appears as though the service continues to write to the database. I know this because I put a Debug.WriteLine() where the writing occurs.
More info on the service:
I am attempting to construct my service in a fashion that allows it to write to the database asynchronously. This is accomplished by using a combination of threads and the ThreadPool.
public void StartDataReceiver() // Entry point to service from WPF host
{
// setup zmq subscriber socket
receiverThread = new Tread(SpawnReceivers);
receiverThread.Start();
}
internal void SpawnReceivers()
{
while(!stopEvent.WaitOne(0))
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessReceivedData), subscriber.Recv()); // subscriber.Recv() blocks when there is no data to receive (according to the zmq docs) so this loop should remain under control, and threads only created in the pool when there is data to process.
}
}
internal void ProcessReceivedData(Object recvdData)
{
// cast recvdData from object -> byte[]
// convert byte[] -> JSON string
// deserialize JSON -> MyData
using (MyDataEntities context = new MyDataEntities())
{
// build up EF model object
Debug.WriteLine("Write obj to db...");
context.MyDatas.Add(myEFModel);
context.SaveChanges();
}
}
internal void QData(Object recvdData)
{
Debug.WriteLine("Queued obj in queue...");
q.Enqueue((byte[])recvdData);
}
public void StopDataReceiver()
{
stopEvent.Set();
receiverThread.Join();
subscriber.Dispose();
zmqContext.Dispose();
stopEvent.Reset();
}
The above code are the methods that I am concerned with. When I debug the WPF host, and the method ProcessReceivedData is set to be queued in the thread pool everything seems to work as expected, until I stop the service by calling StopDataReceiver. As far as I can tell the thread pool never queues any more threads (I checked this by placing a break point on that line), but I continue to see "Write obj to db..." in the output window and when I 'Break All' in the debugger a little green arrow appears on the context.SaveChanges(); line indicating that is where execution is currently halted. When I test some more, and have the thread pool queue up the method QData everything seems to work as expected. I see "Queued obj in queue..." messages in the output window until I stop the service. Once I do no more messages in the output window.
TL;DR:
I don't know how to determine if the Entity Framework is just slowing things way down and the messages I am seeing are just the thread pool clearing its backlog of work items, or if there is something larger at play. How do I go about solving something like this?
Would a better solution be to queue the incoming JSON strings as byte[] like I do in the QData method then have the thread pool queue up a different method to work on clearing the queue. I feel that that solution will only shift the problem around and not actually solve it.
Could another solution be to write a new service dedicated to clearing that queue? The problem I see with writing another service would be that I would probably have to use WCF (or possibly zmq) to communicate between the two services which would obviously add overhead and possibly become less performant.
I see the critical section in all of this being the part of getting the data off the wire fast enough because the publisher I am subscribed to is set to begin discarding messages if my subscriber can't keep up.
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've been asked to write a method that will allow a caller to send a command string to a hardware device via the serial port. After sending the command the method must wait for a response from the device, which it then returns to the caller.
To complicate things the hardware device periodically sends unsolicited packets of data to the PC (data that the app must store for reporting). So when I send a serial command, I may receive one or more data packets before receiving the command response.
Other considerations: there may be multiple clients sending serial commands potentially at the same time as this method will form the basis of a WCF service. Also, the method needs to be synchronous (for reasons I won't go into here), so that rules out using a callback to return the response to the client.
Regarding the "multiple clients", I was planning to use a BlockingCollection<> to queue the incoming commands, with a background thread that executes the tasks one at a time, thus avoiding serial port contention.
However I'm not sure how to deal with the incoming serial data. My initial thoughts were to have another background thread that continually reads the serial port, storing data analysis packets, but also looking for command responses. When one is received the thread would somehow return the response data to the method that originally sent the serial command (which has been waiting ever since doing so - remember I have a stipulation that the method is synchronous).
It's this last bit I'm unsure of - how can I get my method to wait until the background thread has received the command's response? And how can I pass the response from the background thread to my waiting method, so it can return it to the caller? I'm new to threading so am I going about this the wrong way?
Thanks in advance
Andy
First of all: When you use the SerialPort class that comes with the framework, the data received event is asynchronous already. When you send something, data is coming in asynchronously.
What I'd try is: queue all requests that need to wait for an answer. In the overall receive handler, check whether the incoming data is the answer for one of the requests. If so, store the reply along with the request information (create some kind of state class for that). All other incoming data is handled normally.
So, how to make the requests wait for an answer? The call that is to send the command and return the reply would create the state object, queue it and also monitor the object to see whether an answer was received. If an answer was received, the call returns the result.
A possible outline could be:
string SendAndWait(string command)
{
StateObject state = new StateObject(command);
state.ReplyReceived = new ManualResetEvent(false);
try
{
SerialPortHandler.Instance.SendRequest(command, state);
state.ReplyReceived.WaitOne();
}
finally
{
state.ReplyReceived.Close();
}
return state.Reply;
}
What's SerialPortHandler? I'd make this a singleton class which contains an Instance property to access the singleton instance. This class does all the serial port stuff. It should also contain an event that is raised when "out of band" information comes in (data that is not a reply to a command).
It also contains the SendRequest method which sends the command to the serial device, stores the state object in an internal list, waits for the command's reply to come in and updates the state object with the reply.
The state object contains a wait handle called ReplyReceived which is set by the SerialPortHandler after it has changed the state object's Reply property. That way you don't need a loop and Thread.Sleep. Also, instead of calling WaitOne() you could call WaitOne(timeout) with timeout being a number of milliseconds to wait for the reply to come in. This way you could implement some kind of timeout-feature.
This is how it could look in SerialPortHandler:
void HandlePossibleCommandReply(string reply)
{
StateObject state = FindStateObjectForReply(reply);
if (state != null)
{
state.Reply = reply;
state.ReplyReceived.Set();
m_internalStateList.Remove(state);
}
}
Please note: This is what I'd try to start with. I'm sure this can be very much optimized, but as you see there's not much "multithreading" involved where - only the SendAndWait method should be called in a way so that multiple clients can issue commands while another client is still waiting for its response.
EDIT
Another note: You're saying that the method should form the basis for a WCF service. This makes things easier, as if you configure the service right, a instance of the service class will be created for every call to the service, so the SendAndWait method would "live" in its own instance of the service and doesn't even need to be re-entrant at all. In that case, you just need to make sure that the SerialPortHandler is always active (=> is created and running independently from the actual WCF service), no matter whether there's currently an instance of your service class at all.
EDIT 2
I changed my sample code to not loop and sleep as suggested in the comments.
If you really want to block until the background thread has received your command response, you could look into having the background thread lock an object when you enqueue your command and return that to you. Next, you wait for the lock and continue:
// in main code:
var locker = mySerialManager.Enquee(command);
lock (locker)
{
// this will only be executed, when mySerialManager unlocks the lock
}
// in SerialManager
public object Enqueue(object command)
{
var locker = new Object();
Monitor.Enter(locker);
// NOTE: Monitor.Exit() gets called when command result
// arrives on serial port
EnqueueCommand(command, locker);
return locker;
}
A couple things. You need to be able to tie up serial responses to the commands that requested them. I assume that there's some index or sequence number that goes out with the command and comes back in the response?
Given that, you should be OK. You need some sort of 'serialAPU' class to represent the request and response. I don't know what these are, maybe just strings, I don't know. The class should have an autoResetEvent as well. Anyway, in your 'DoSerialProtocol()' function, create a serialAPU, load it up with request data, queue it off to the serial thread and wait on the autoResetEvent. When the thread gets the serialAPU, it can store an index/sequence number in the serialAPU, store the serialAPU in a vector and send off the request.
When data comes in, do you protocol stuff and, if the data is a valid response, get the index/sequence from the data and look up the matching value in the serialAPU's in the vector. Remove the matching serialAPU from the vector, load it up with the response data and signal the autoResetEvent. The thread that called 'DoSerialProtocol()' originally will then run on and can handle the response data.
There are lots of 'wiggles' of course. Timeouts is one. I would be tempted to have a state enum in the serialAPU, protected by a CritcalSection or atomicCompareandSwap, initialized ot 'Esubmitted'. If the oringinating thread times out its wait on the autoResetEvent, it tries to set the state enum in its serialAPU to 'EtimedOut'. If it succeeds, fine, it returns an error to the caller. Simlarly, in the serial thread, if it finds a serialAPU whose state is EtimedOut, it just removes it from the container. If it finds the serialAPU that matches response data, it tries to change the state to 'EdataRx' and if it succeeds. fires the autoRestEvent.
Another is the annoying OOB data. If that comes in, create a serialAPU, load in the OOB data, set the state to 'EOOBdata' and call some 'OOBevent' with it.
I would advise you to look at the BackgroundWorker-Class
Ther is a Event in this class (RunWorkerCompleted) which is fired when the worker has finished his job.
I am writing a C# console application that connects to a server trough TCP, it uses a separate thread to listen for incoming messages from the server and I want it to write them to the console while at the same time reading a message from the console. I was able to do that, but I have a problem.
The console displays this while I type and a messages comes in:
msg from server
msg from server
my msmsg from server
g to server
And i want it to separate my message from the servers mesages like so:
msg from server
msg from server
msg from server
my msg to server
If I receive a message I still want to keep my typed message, but I don't want it to mix up with the received message, I want it to remain complete on the last line.
Can I do that? And how?
Can I shift my message to the end of the console, when a message from the server comes in?
I believe this is in fact possible with the standard .NET Console API, using a bit of hackery. What you need to do is create an asynchronous Read/ReadLine method (which I assume you have already done, judging by your post) and allow it to be cancelled as soon as new data arrives. I'm going to assume you're sending input line by line for now. The pseudocode for the "new data handler" might be something like this:
Save the current input buffer.
Cancel the current asynchronous read.
Reset the cursor position to the end of the last writing of new data.
Output the new data.
Save the cursor position.
Restart the asynchronous read event.
In particular, you'll need to mess around with Console.CursorLeft and Console.CursorTop properties. You might be able to avoid some of the hackery by interfacing with the Win32 API console functions directly, but it's possibly not worth the bother.
Hope that helps.
You can't do this directly via the BCL in C#. There are two main alternatives, though.
1) Turn this into a GUI app, and have separate input/output areas. This is the most "clear" option from a user's POV, but requires a GUI app instead of a console app.
2) P/Invoke into the console API directly. This gives you complete control of the console's view, point by point. See SetConsoleCursorPosition and WriteConsole, etc.
You need to use a lock on some object to stop both threads using the console at the same time. Declare something like this:
public static class ThreadSafeConsole
{
private static object _lockObject = new object();
public static void WriteLine(string str)
{
lock (_lockObject)
{
Console.WriteLine(str);
}
}
}
Now call ThreadSafeConsole.WriteLine instead of Console.WriteLine.
If I understand you correctly, you'd have to define what the beginning and ending of 'typing to console' is for your application so that you can still lock on an object while that is happening, and not inserting messages from your listener thread into your typed text.
public static Object consoleLock = new Object();
public static void Main(string[] args)
{
lock (consoleLock)
{
// now nothing can write to the console (if it's trying to lock onto it)
Console.WriteLine("Please Input Something");
// read from console
}
// now, your separate thread CAN write to the console - without
// interrupting your input process
}