I have a hardware component that I use with TCP communication. The class that control it has 3 jobs: Trigger the device, listen to incoming messages and raise an event when a message is received:
public class Hardware
{
public event Action<string> OnHardwareMessage;
private NetworkStream stream = new NetworkStream();
public Hardware()
{
Task.Factory.StartNew(() => { Listen(); });
}
private void Listen()
{
//listen to TCP port and raise an event when a message is received
byte[] bytes = new byte[1024];
int bytesRead = stream.Read(bytes, 0, bytes.Length);
string response = Encoding.ASCII.GetString(bytes, 0, bytesRead);
if (OnHardwareMessage != null)
OnHardwareMessage(response);
}
public void Trigger()
{
//Trigger the hardware component
//the response usually takes up to 5 seconds to arrive
}
}
This class is used in a loop inside a view-model:
public class MainViewModel
{
private static EventWaitHandle hardwareWaiter =
new EventWaitHandle(false, EventResetMode.AutoReset);
private Hardware hardware = new Hardware();
//what i'm doing now is holding a field for incoming event results
private string hardwareResult;
public MainViewModel()
{
hardware.OnHardwareMessage += hardware_OnHardwareMessage;
while (true)
{
hardware.Trigger();
if (hardwareWaiter.WaitOne(10000))
{
//is it possible to read the event argument here?
//do something with the event argument
someObservableCollection.Add(hardwareResult);
//clear the value
hardwareResult = string.Empty;
}
else
{
throw new Exception("Hardware did not respond on time");
}
}
}
//event listener for hardware events
private void hardware_OnHardwareMessage(string message)
{
hardwareResult = message;
hardwareWaiter.Set();
}
}
What I do is trigger the device and wait for up to 10 seconds for a response. What I'm doing now is holding a class scoped field, assign the message received inside the event listener, read it in the inside the loop and clear it.
My question is if there's any built in mechanism that could let me read the event argument directly after the EventWaitHandle was signaled (outside the event listener).
I would not base this on events. Maybe your listener should expose a BlockingCollection that represents the incoming stream of messages. Readers can then take from that collection with a timeout. If the timeout hits no message is taken and lost (this is a race condition that you have right now).
If you insist on using events use a closure to thread the message state:
string hardwareResult = null;
Action handler = (...) =>
{
hardwareResult = message;
hardwareWaiter.Set();
};
hardware.OnHardwareMessage += handler;
That way you only need a local variable which is scoped more tightly than a field.
There's the usual TCP bug as well: You assume to read an entire message. You could read one byte at a time instead.
Related
So basically I want my server to raise an event (or a callback) when a connected client sends data. I can't come up with a solution to this problem and can't find anything online after days of searching.
What I've thought of was making an asynchronous foreach loop that looped through all the connected users, and check if there is any data to be read on each one (using TcpClient.Avaliable, but a network stream could also check this) but an infinite loop like this without any stop would be bad practice and use an insane amount of resources (from what I understand at least, I am new to threading and networking).
There is logic I need to be executed whenever the server gets data from a client (in this case a message, because it's a chat application), basically broadcast it to every other user, but I just can't find out how to detect if any user has sent data so that it raises an event to broadcast the message, log the message, etc...
Please be "soft" with the explanations as I am new to threading/networking and ty in advance.
As per request here is my code, take note that it is prototype-y and a bit unfinished, but I'm sure it gets the point across:
//Properties
public List<User> ConnectedUsers { get; private set; } = new List<User>();
public TcpListener listener { get; set; }
public bool IsListeningForConnections { get; set; }
public int DisconnectionCheckInterval { get; set; } //in seconds
//Events
public event EventHandler<ServerEventArgs> UserConnected;
public event EventHandler<ServerEventArgs> MessageReceived;
public NetworkManager()
{
listener = new TcpListener(IPAddress.Parse("192.168.1.86"), 6000); //binds // TODO: Change to: user input / prop file
DisconnectionCheckInterval = 10;
IsListeningForConnections = false;
}
public async void StartListeningForConnections()
{
IsListeningForConnections = true;
listener.Start();
while (IsListeningForConnections)
{
User newUser = new User();
newUser.TcpClient = await listener.AcceptTcpClientAsync();
OnUserConnected(newUser); // raises/triggers the event
}
}
public void StartListeningForDisconnections()
{
System.Timers.Timer disconnectionIntervalTimer = new System.Timers.Timer(DisconnectionCheckInterval * 1000);
//TODO: setup event
//disconnectionIntervalTimer.Elasped += ;
disconnectionIntervalTimer.AutoReset = true;
disconnectionIntervalTimer.Enabled = true;
//disconnectionIntervalTimer.Stop();
//disconnectionIntervalTimer.Dispose();
}
public async void StartListeningForData()
{
//??????????
}
public async void SendData(string data, TcpClient recipient)
{
try
{
byte[] buffer = Encoding.ASCII.GetBytes(data);
NetworkStream stream = recipient.GetStream();
await stream.WriteAsync(buffer, 0, buffer.Length); //await
Array.Clear(buffer, 0, buffer.Length);
}
catch { } //TODO: handle exception when message couldn't be sent (user disconnected)
}
public string ReceiveData(TcpClient sender)
{
try
{
NetworkStream stream = sender.GetStream();
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
return Encoding.ASCII.GetString(buffer).Trim('\0');
}
catch
{
return null; //TODO: handle exception when message couldn't be read (user disconnected)
}
}
protected virtual void OnUserConnected(User user)
{
ConnectedUsers.Add(user);
UserConnected?.Invoke(this, new ServerEventArgs() { User = user });
}
protected virtual void OnMessageReceived(User user, Message message) //needs trigger
{
MessageReceived?.Invoke(this, new ServerEventArgs() { User = user, Message = message });
}
basically a different class will call all the 3 classes that start with "StartListeningForX", then one of the 3 corresponding events are raised when one of the checks goes through (disconnection/connection/new message), and process that data, I just can't get my hands on how to call an event when a new message arrives for each user.
What I've thought of was making an asynchronous foreach loop that looped through all the connected users, and check if there is any data to be read on each one (using TcpClient.Avaliable, but a network stream could also check this) but an infinite loop like this without any stop would be bad practice and use an insane amount of resources
The standard practice is to have an "infinite" loop for each connected client, so that there is always a read going on every socket. I put "infinite" in quotes because it will actually eventually stop; either by reading 0 bytes (indicating end of stream) or by receiving an exception (indicating a broken connection).
I am new to threading/networking
It's funny how often I see developers trying to learn networking and threading at the same time. Let me be clear: threading and TCP/IP sockets are both extremely complicated and take quite a bit of time to learn all the sharp corners. Trying to learn both of these topics at once is insane. I strongly recommend choosing one of them to learn about (I'd recommend threading first), and only after that one is mastered, proceed to the other.
RabbitMQ
If you have access to the client side code, I'd consider using something like RabbitMQ, or a similar queue service. This allows to link the different apps together through a message broker or queue, and get messages/events real time.
There are functions you can call on event received.
I have one main form class and another class. In the second class, I have a thread loop:
public void StartListening()
{
listening = true;
listener = new Thread(new ThreadStart(DoListening));
listener.Start();
}
// Listening for udp datagrams thread loop
/*=====================================================*/
private void DoListening()
{
while (listening)
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.ASCII.GetString(content);
delegMessage(message);
}
}
}
// Stop listening for udp datagrams
/*=====================================================*/
public void StopListening()
{
lock (locker)
{
listening = false;
}
}
In main form class, I start this listening in class constructor
udp.StartListening();
And than, in this main form class, I have key hook event, too. In this event, I wan to stop thread running in the second class.
private void hook_KeyPressed(int key)
{
if (key == (int)Keys.LMenu)
altPressed = true;
if (key == (int)Keys.F4 && altPressed == true)
udp.StopListening();
}
Unfortunetely, the thread is still running.
Do you have some ideas about this??
Thank you very much.
Your thread is blocking at the byte[] content = udpClient.Receive(ref remoteIPEndPoint); line. The Receive method blocks until something is received.
You should use the asynchronous version (BeginReceive) instead.
Also, another flaw in your code - you check for the stopping condition without any synchronization. Here:
private void DoListening()
{
while (listening){ //this condition could stuck forever in 'false'
}
Actually, without a memory barrier, there is no guarantee, that a thread, that is running DoListening will ever see the change to listening var from other thread. You should at least use locking here (which provides memory barrier)
As #igelineau pointed out - your code is blocking on the receive call. If you don;t want to go down the async route (which I'd recommend) just send something to the udp port in your stop listening method.
I'm developing a communication API to be used by a lot of generic clients to communicate with a proprietary system.
This proprietary system exposes an API, and I use a particular classes to send and wait messages from this system: obviously the system alert me that a message is ready using an event. The event is named OnMessageArrived.
My idea is to expose a simple SendSyncMessage(message) method that helps the user/client to simply send a message and the method returns the response.
The client:
using ( Communicator c = new Communicator() )
{
response = c.SendSync(message);
}
The communicator class is done in this way:
public class Communicator : IDisposable
{
// Proprietary system object
ExternalSystem c;
String currentRespone;
Guid currentGUID;
private readonly ManualResetEvent _manualResetEvent;
private ManualResetEvent _manualResetEvent2;
String systemName = "system";
String ServerName = "server";
public Communicator()
{
_manualResetEvent = new ManualResetEvent(false);
//This methods are from the proprietary system API
c = SystemInstance.CreateInstance();
c.Connect(systemName , ServerName);
}
private void ConnectionStarter( object data )
{
c.OnMessageArrivedEvent += c_OnMessageArrivedEvent;
_manualResetEvent.WaitOne();
c.OnMessageArrivedEvent-= c_OnMessageArrivedEvent;
}
public String SendSync( String Message )
{
Thread _internalThread = new Thread(ConnectionStarter);
_internalThread.Start(c);
_manualResetEvent2 = new ManualResetEvent(false);
String toRet;
int messageID;
currentGUID = Guid.NewGuid();
c.SendMessage(Message, "Request", currentGUID.ToString());
_manualResetEvent2.WaitOne();
toRet = currentRespone;
return toRet;
}
void c_OnMessageArrivedEvent( int Id, string root, string guid, int TimeOut, out int ReturnCode )
{
if ( !guid.Equals(currentGUID.ToString()) )
{
_manualResetEvent2.Set();
ReturnCode = 0;
return;
}
object newMessage;
c.FetchMessage(Id, 7, out newMessage);
currentRespone = newMessage.ToString();
ReturnCode = 0;
_manualResetEvent2.Set();
}
}
I'm really noob in using waithandle, but my idea was to create an instance that sends the message and waits for an event. As soon as the event arrived, checks if the message is the one I expect (checking the unique guid), otherwise continues to wait for the next event.
This because could be (and usually is in this way) a lot of clients working concurrently, and I want them to work parallel.
As I implemented my stuff, at the moment if I run client 1, client 2 and client 3, client 2 starts sending message as soon as client 1 has finished, and client 3 as client 2 has finished: not what I'm trying to do.
Can you help me to fix my code and get my target?
Thanks!
autoResetEvent - controls a main connection life cycle. I do not see where you release this handle by calling Set() so OnMessageArrived event is unsubscribed
autoResetEvent2 - controls incomming messages, you shall set this event only if a message with expected GUID is received, basically just
if (guid == currentGUI.ToString())
{
autoResetEvent2.Set();
}
Also use more clear and descriptive names for variables so it will be easier to write and understand a code
I'm currently writing a component to communicate with an Ethernet based device and am having to use asynchronous sockets. At times when I receive specific 'commands' from the device, I need to raise an event for whatever program is using my component (most usually a WinForm.) I'm creating a sample form for the user but I am having difficulty allowing the client form to receive the events and modify the form; I'm getting the typical "Cross-thread operation not valid: Control 'listStrings' accessed from a thread other than the thread it was created on."
I've tried reading over Implementing the Event-based Asynchronous Pattern, and Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern, though it doesn't quite seem to be exactly what I need, especially when reading "Opportunities for Implementing the Event-based Asynchronous Pattern" in the first link.
.Net / C# is more of a hobby than profession, and in this project - this is the last piece I need to figure out before being able to complete it. Would it be better to use a "thread-safe" (I know, everyone throws that term around like it only means one thing) existing TCP/IP component rather than trying to implement it myself?
EDIT: Here's my network class code to show you how I'm implementing it now. I forget where I came across this snippet, but it's worked fine up until I've added the form.
internal class Network
{
private Device dev;
private TcpClient client;
private NetworkStream ns;
private byte[] buffer = new byte[2048];
private Queue<byte[]> _msgQ = new Queue<byte[]>();
public Network(Device d)
{
dev = d;
}
internal void Connect(string ipAddress, int port)
{
client = new TcpClient();
client.BeginConnect(ipAddress, port, new AsyncCallback(OnConnect), null);
}
internal byte[] getLocalIp()
{
return ((IPEndPoint)client.Client.LocalEndPoint).Address.GetAddressBytes();
}
private void OnConnect(IAsyncResult ar)
{
try
{
client.EndConnect(ar);
ns = new NetworkStream(client.Client);
ns.BeginRead(buffer, 0, 2048, new AsyncCallback(OnRead), null);
while (_msgQ.Count > 0)
{
byte[] message = _msgQ.Dequeue();
ns.Write(message, 0, message.Length);
}
dev.dvDevice._connected = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
internal void Disconnect()
{
try
{
client.Close();
dev.dvDevice._connected = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
internal void Write(byte[] message)
{
if ((!client.Connected) || ns == null)
{
_msgQ.Enqueue(message);
return;
}
ns.Write(message, 0, message.Length);
}
private void OnWrite(IAsyncResult ar)
{
try
{
ns.EndWrite(ar);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void OnRead(IAsyncResult ar)
{
try
{
int recv = ns.EndRead(ar);
byte[] message = new byte[recv];
Buffer.BlockCopy(buffer, 0, message, 0, recv);
dev.dvDevice._mh.Parse(message);
ns.BeginRead(buffer, 0, 2048, new AsyncCallback(OnRead), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Device is the class which is exposed to the client. It contains a MessageHandler (_mh) class which does all the parsing. Device contains the public event which is called by the MessageHandler on specific responses. Hopefully this helps in what I have so far; I'd prefer not having to rewrite too much, but to make it right (and work properly), I will if I must.
EDIT (2):
My goal for this library is that the user should not at all have to manage any of the threads - so when an event is raised, say "ReceiveString", the user should just be able to act on it without any thought.
EDIT (3):
More code for completeness.
public delegate void OnStringEvent(byte[] str);
public class Device
{
internal struct _device
{
// other stuff too, but here's what's important
public bool _connected;
public bool _online;
public MessageHandler _mh;
public Network _net;
}
public event OnStringEvent OnString;
internal void ReceiveString(byte[] str)
{
OnString(str);
}
internal _device dvDevice;
public Device(int device_number, int system_number)
{
dvDevice = new _device(device_number, system_number);
dvDevice._mh = new MessageHandler(this);
dvDevice._net = new Network(this);
}
}
internal class MessageHandler
{
private Device dev;
public MessageHandler(Device d)
{
dev = d;
}
public void Parse(byte[] message)
{
// The code goes through the message and does what it needs to
// and determines what to do next - sometimes write back or something else
// Eventually if it receives a specific command, it will do this:
dev.ReceiveString(ParseMessage(ref _reader));
}
}
Do youself a favor and rely on TPL to do the synchronization lifting for you. Example:
NetworkStream stream = MySocket.NetworkStream;
// creat a Task<int> returning the number of bytes read based on the Async patterned Begin- and EndRead methods of the Stream
Task<int> task = Task<int>.Factory.FromAsync(
fs.BeginRead, fs.EndRead, data, 0, data.Length, null);
// Add the continuation, which returns a Task<string>.
return task.ContinueWith((task) =>
{
if (task.IsFaulted)
{
ExceptionTextBox.Text = task.Exception.Message;
}
else
{
ResultTextBox.Text = string.Format("Read {0} bytes into data", task.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
I like #Polity's answer, being an Rx fan I would say use Rx (Reactive Extensions)
//we convert a typical begin/end (IAsyncPattern) into an observable sequence
//it returns a Func -read() that takes a byte, two ints and returns one.
var read = Observable.FromAsyncPattern<byte[], int, int, int>
(networkStream.BeginRead, networkStream.EndRead)
.ObserveOn(Scheduler.Dispatcher);
// Now, you can get an IObservable instead of an IAsyncResult when calling it.
byte[] someBytes = new byte[10];
IObservable<int> observable = read(someBytes, 0, 10);
observable.Subscribe(x=>
//x will be the returned int. You can touch UI from here.
);
Based on your code I can see that another thread calls the OnString event, then I assume when you subcribe to it, you're just adding the string into the listbox.
device.OnString += new OnStringEvent(device_onstring);
void device_onstring(byte[] str)
{
listStrings.Items.Add(...);//this is wrong, will give cross thread op error.
//you do this:
this.Invoke(new MethodInvoker(delegate()
{
listStrings.Items.Add(..);
//or anything else that touches UI
});
// this should refer to a form or control.
}
You can handle this in 2 places depending on your design. If the event is raised from a different thread you can handle it in the event handler by checking the .invokeReqeuired property of the form( or other control) handling the event. If it returns true you should use the .beginInvoke method to marshal the call to the proper thread.
Depending on your design you can handle it from the other end by passing your component an instance of the form you want to marshal to. Before you raise the event, check .invokeRequired and marshal the call so that the event is raised in the proper thread. This way the code using your library doesn't have to worry about threads, but it required that your library have a reference to system.windows.forms.
This should be a pretty easy problem to solve: you just need to execute any code in your form that updates controls using Invoke.
The precise implementation will depend on how the async code is calling back into your form. If you add that code to your question, we can provide a more complete answer.
I currently have a client-server application that involves a Silverlight client and a .NET server. The .NET portion uses the Tcp classes provided in System.Net.Sockets namespace whereas the Silverlight client uses raw sockets. I'm porting into this from code that currently uses the HttpListener classes because it doesn't suit my needs. The Http classes, though, have on the SL side the ability to use Begin* and End* style asynchronous methods that allow me to specify a handler once the operation has completed. I'm having trouble getting this to work with the new system. My current strategy is to include the handler as part of the UserToken. However, it seems that this token is not getting updated.
Here is some redacted code. I am able to get the two sides to talk to each other, but it seems the correct UserToken is not being sent.
public class ClientUserToken
{
public Handler Handler { get; set; }
public string Test { get; set; }
public ClientUserToken(Handler handler, string test)
{
Handler = handler;
Test = test;
}
}
public class SocketClient
{
private Socket _clientSocket;
private string _ipAddress;
private int _port;
private void OpenSocket()
{
var endPoint = new DnsEndPoint(_ipAddress, _port);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.UserToken = new ClientUserToken(null, "foo");
args.RemoteEndPoint = endPoint;
args.Completed += OnSocketCompleted;
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_clientSocket.ConnectAsync(args);
}
void OnSocketCompleted(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect: ProcessConnect(e); break;
case SocketAsyncOperation.Receive: ProcessReceive(e); break;
case SocketAsyncOperation.Send: ProcessSend(e); break; // this never gets called
}
}
void ProcessConnect(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
byte[] response = new byte[1024];
e.SetBuffer(response, 0, response.Length);
_clientSocket.ReceiveAsync(e);
}
}
void ProcessReceive(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
{
var userToken = e.UserToken as ClientUserToken; // this token is always the one set in ProcessConnect
// process the data
if (!_clientSocket.ReceiveAsync(e))
{
ProcessReceive(e);
}
}
}
// this is never called, for some reason
void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
var userToken = e.UserToken as ClientUserToken;
if (!_clientSocket.ReceiveAsync(e))
{
ProcessReceive(e);
}
}
}
// this is the public API that users use to actually send data across
public void SendToServer(byte[] data, int len, Handler handler)
{
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.UserToken = new ClientUserToken(handler, "bar");
args.SetBuffer(data, 0, len);
if (!_clientSocket.SendAsync(args))
{
ProcessReceive(args);
}
}
}
As the comments above suggest, in ProcessReceive, userToken.Test is always "foo" and userToken.Handler is always null.
I have so far not been able to break into ProcessSend so I can't see what SocketAsyncEventArgs it actually sent. Anyone have a clue why this event isn't firing (Completed after a Send)? Am I screwing up my SendToServer function?
I realize there may be other existing problems with synchronization and such, but I don't think that's the issue here. One thing I did try was setting up a ManualResetEvent to ensure that no one sends data to the server before the connection has been completed (ProcessConnect) but that did not solve the issue, either.
Any help will be appreciated!
EDIT: So the reason this is happening is because when I call ReceiveAsync in the ProcessConnect function, it is being used when the server is sending back the response for my data. Hence, UserToken "foo" is present in the handler. The next time the server sends data, the ReceiveAsync uses the args with the UserToken "bar". So it is kind of out of sync, for the duplex communication bit. I can't ensure that the SocketAsyncEventArgs that I sent from the client-side is the same one that is used on the response. It seems like the only solution is to have the SL client open two sockets--one for server-initiated data and the other for client-initiated requests. However, this means I'm not taking advantage of the duplex nature.
This model won't work because I'm creating a new SocketAsyncEventArgs on each send, which means that the data can come back on any of these args. I've been moving towards a model with a pool of SocketAsyncEventArgs and each client can only have one request/response at a time.