XSockets Client Connecting But Not Receiving Messages - c#

I'm trying to set up a specific scenario but, obviously, I'm having problems. My server is a site that primarily hosts a WCF service but I want to add an XSockets host there as well. I have the standard code in the bootstrap code file as per the instructions in the readme.txt. Upon a client connection, I am starting a worker thread which is basically a heartbeat that the client will monitor. The relevant code from the controller is as follows:
public class HeartbeatController : XSocketController
{
public void AddMessage(string message)
{
this.SendToAll(message, "addMessage");
}
}
Within my worker thread I am calling this:
string message = String.Format("pump", Math.Round(cpuCounter.NextValue());
ClientPool connection = ClientPool.GetInstance("ws://mywebsite:4502/HeartbeatController", "*");
connection.Send(message, "addMessage");
Currently I'm testing this with a console client which looks like this:
class Program
{
static XSocketClient socketClient;
static void Main(string[] args)
{
Console.WriteLine("Starting client...");
string url = "ws://mywebsite:4502/HeartbeatController";
socketClient = new XSocketClient(url, "*");
socketClient.OnOpen += socketClient_OnOpen;
socketClient.Open();
while (true)
{
// let it sit and display the "pump" messages
string input = Console.ReadLine();
if (input.Equals("Q", StringComparison.Ordinal))
{
break;
}
}
}
static void socketClient_OnOpen(object sender, EventArgs e)
{
Console.WriteLine("socketClient Opened");
socketClient.Bind("addMessage", OnAddMessage);
}
private static void OnAddMessage(ITextArgs textArgs)
{
Console.WriteLine("AddMessage :: {0}", textArgs.data);
}
}
On the client, if I put a breakpoint in the socketClient_OnOpen method it gets hit so I think it is connecting. But the pump message never makes it to the client.
Two Questions:
Is there anything obvious that I'm missing?
(Unrelated) Since many enterprises really don't like punching holes in their firewalls, is there any way to use port 80 with this setup (so that the client connection would look like "ws://mywebsite/HeartbeatController")?
Thanks for any help!

So to see what your pump actually was sending in to the server I added a custom pipeline.
public class MyPipeline : XSocketPipeline
{
//Incomming textmessage
public override void OnMessage(IXSocketController controller, ITextArgs e)
{
Console.WriteLine("IN " + e.data);
//Let the message continue into the server
base.OnMessage(controller, e);
}
//Outgoing textmessage
public override ITextArgs OnSend(IXSocketProtocol protocol, ITextArgs e)
{
Console.WriteLine("OUT " + e.data);
return base.OnSend(protocol, e);
}
}
Since I then saw that you was sending in a string that actually did not have a property named "message". The actionmethod "AddMessage" expects you to pass in a property message of type string. So you can solve this in two ways, both of them are simple.
Just replace the string parameter in the AddMessage with ITextArgs
public void AddMessage(ITextArgs message)
or...
Pass in a object from your worker thread instead of a string like this
connection.Send(new {message}, "addMessage");
So all you need to do to get it to work is to change this row
connection.Send(message, "addMessage");
with this row
connection.Send(new {message}, "addMessage");
EDIT: Btw, 4.0 is on the way and the client will be very much improved as well as the serverside stuff.

Related

asp.net and multi threading and C# object

I'm new to ASP.net programming and I don't really understand the thing about multi threading . When I debug in my ASP.net app/website it shows a tab that I'm not familiar with: Parallel watch, it's something about multi threading. When I search about multi threading I only find examples about how to use multi-threading etc. The thing is, I'm not using any class for threading.
What I got in my code:
is my main page:
Index.aspx.cs:
protected void Button1_Click(object sender, EventArgs e)
{
string Message = PLC1.Connect();
lblClock.Text = Message;
}
and
protected void Timer1_Tick(object sender, EventArgs e)
{
if(PLC1.x_ConnectionEstablished)
{
string Message;
Message = PLC1.ReadDB(1, 0, 17);
if (Message == "OK")
{
lblClock.Text = "Connected and retrieved value!!";
}
else
{
lblClock.Text = Message;
}
}
else
{
lblClock.Text = "No connection! Press the button!";
}
}
my class: PLC.cs:
public string Connect()
{
int Result;
string Message;
Result = s7_S7Client.ConnectTo(s_IP, i_Rack, i_Slot);
Message = s7_S7Client.ErrorText(Result);
x_ConnectionEstablished = s7_S7Client.Connected();
return Message;
}
public string ReadDB(int a_DBnr, int a_startPos, int a_size)
{
int Result;
string Message = "";
try
{
Result = s7_S7Client.DBRead(a_DBnr, a_startPos, a_size, bArray_Buffer);
Message = s7_S7Client.ErrorText(Result);
}
catch (Exception E)
{
Message = E.Message;
}
return Message;
}
When I press the button (while debugging) it jumps to the Connect() of my PLC class. And it actually gives true on the x_ConnectionEstablished. But when my Timer triggers it doesn't go into my if-statement. Since it's saying: x_ConnectionEstablished = false.
I can add the code to the timer, but I don't want to execute the connection method each time I get in the timer(that's what I'm using this x_connectionEstablished for.
So my question is how does this threading work and how can I get my website running decently with or without the threading?
Your PLC1 and s7_S7Client appear to create some kind of persistent connection, for example through TCP sockets or a serial connection.
You don't want to create connections like this from an HTTP back-end, because HTTP is (or at least supposed to be) stateless: each request starts with a clean slate, all your variables (and thus connections) from the previous request are gone.
So I would advise wrapping this logic into a Windows Service that manages connecting to the PLC, and exposing the logic from this service through WCF.
Then your web application can issue requests, through WCF, to the service, and the service in turn talks to the PLC and maintains the connection.

.NET Client - Waiting for an MQTT response before proceeding to the next request

I have a MQTT calls inside a loop and in each iteration, it should return a response from the subscriber so that I could use the value being forwarded after I published. But the problem is I don't know how would I do it.
I hope you have an idea there or maybe if I'm just not implementing it right, may you guide me through this. Thanks.
Here's my code:
// MyClientMgr
class MyClientMgr{
public long CurrentOutput { get; set; }
public void GetCurrentOutput(MyObjectParameters parameters, MqttClient client)
{
MyMessageObject msg = new MyMessageObject
{
Action = MyEnum.GetOutput,
Data = JsonConvert.SerializeObject(parameters)
}
mq_GetCurrentOutput(msg, client);
}
private void mq_GetCurrentOutput(MyMessageObject msg, MqttClient client)
{
string msgStr = JsonConvert.SerializeObject(msg);
client.Publish("getOutput", Encoding.UTF8.GetBytes(msgStr),
MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
client.MqttMsgPublishReceived += (sender, e) =>{
MyObjectOutput output = JsonConvert.DeserializeObject<MyObjectOutput>(Encoding.UTF8.GetString(e.Message));
CurrentOutput = output;
};
}
}
// MyServerMgr
class MyServerMgr
{
public void InitSubscriptions()
{
mq_GetOutput();
}
private void mq_GetOutput()
{
MqttClient clientSubscribe = new MqttClient(host);
string clientId = Guid.NewGuid().ToString();
clientSubscribe.Connect(clientId);
clientSubscribe.Subscribe(new string[] { "getOutput" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
MqttClient clientPublish = new MqttClient(host);
string clientIdPub = Guid.NewGuid().ToString();
clientPublish.Connect(clientIdPub);
clientSubscribe.MqttMsgPublishReceived += (sender, e) => {
MyMessageObj msg = JsonConvert.DeserializeObject<MyMessageObj>(Encoding.UTF8.GetString(e.Message));
var output = msg.Output;
clientPublish.Publish("getOutput", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(output)), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
}
}
}
// MyCallerClass
class MyCallerClass
{
var host = "test.mqtt.org";
var myServer = new MyServerMgr(host);
var myClient = new MyClientMgr();
myServer.InitSubscriptions();
MqttClient client = new MqttClient(host);
for(int i = 0; i < 10; i++)
{
long output = 0;
MyObjectParameters parameters = {};
myClient.GetCurrentOutput(parameters, client) // here I call the method from my client manager
// to publish the getting of the output and assigned
// below for use, but the problem is the value doesn't
// being passed to the output variable because it is not
// yet returned by the server.
// Is there a way I could wait the process to
// get the response before assigning the output?
output = myClient.CurrentOutput; // output here will always be null
// because the response is not yet forwarded by the server
}
}
I have a loop in my caller class to call the mqtt publish for getting the output, but I have no idea how to get the output before it was assigned, I want to wait for the response first before going to the next.
I've already tried doing a while loop inside like this:
while(output == 0)
{
output = myClient.CurrentOutput;
}
Yes, I can get the output here, but it will slow down the process that much. And sometimes it will fail.
Please help me. Thanks.
It looks like you are trying to do synchronous communication over an asynchronous protocol (MQTT).
By this I mean you want to send a message and then wait for a response, this is not how MQTT works as there is no concept of a reply to a message at the protocol level.
I'm not that familiar with C# so I'll just give an abstract description of possible solution.
My suggestion would be to use a publishing thread, wait/pulse (Look at the Monitor class) to have this block after each publish and have the message handler call pulse when it has received the response.
If the response doesn't contain a wait to identify the original request you will also need a state machine variable to record which request is in progress.
You may want to look at putting a time out on the wait in case the other end does not respond for some reasons.
You can use AutoResetEvent class that has WaitOne() and Set() methods. Using WaitOne() after publish will wait until the message is published and using Set() under client_MqttMsgPublishReceived event will release the wait when the subscriber received the message he subscribed for.

How can I keep WCF from timing out?

I have a very simple WCF service:
[ServiceContract]
public interface IEngine
{
#region Test code
// test - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[OperationContract]
string Test();
}
implemented as follows:
public partial class Engine : IEngine
{
private static int nTestCount = 0;
string IEngine.Test()
{
try
{
nTestCount++;
}
catch (Exception)
{
}
return "Service OK " + nTestCount.ToString();
}
}
When I call the test service method 10 times, in about 10 seconds... I get this error:
The request channel timed out while waiting for a reply after 00:01:00. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.
( I tried to put in my web.config file but it doesn't show up here )
( help on posting the contents would be appreciated )
Update 1:
Here is the client code that invokes the service:
private void btn_Test_Click(object sender, EventArgs e)
{
ServiceReference1.EngineClient eng = new EngineClient();
textBox1.Text = eng.Test();
}
You are not closing your connections when you are done with them, this is causing the server to tie up a connection until the garbage collector collects your object. The default max open sessions a server can handle is 10 for .net 3.5 and older (it was raised to 100 * ProcessorCount in .NET 4).
Dispose of the engine and it should work fine.
private void btn_Test_Click(object sender, EventArgs e)
{
using(ServiceReference1.EngineClient eng = new EngineClient())
{
textBox1.Text = eng.Test();
}
}
You aren't closing your client connections after each use which after a certain period causes the service to run out of available connections. Once the service reaches its max open connections, new connections will timeout waiting for a connect to clear up.
You need to close your connections when you're done with them by calling their Dispose() or wrapping them in using blocks
private void btn_Test_Click(object sender, EventArgs e)
{
using (ServiceReference1.EngineClient eng = new EngineClient())
{
textBox1.Text = eng.Test();
}
}

how to use string in multiple threads

So I need to have my IP string to be used by 2 threads of my program. I don't know alot about classes and voids but at the time I have it kind of like this:
static void Main(string[] args)
{
string IP = "127.0.0.1"
}
and I want to use it in another thread:
static void th1T()
{
while (true)
{
var ping = new Ping();
ping.Send(IP);
}
}
How can I get that to work? I know I am doing something wrong, but don't know what i shall use instead.
The first issue is that IP is scoped to the method Main. You'll need to declare IP somewhere th1T can get to if you truly want to share it.
static string IP = "127.0.0.1"
static void Main(string[] args)
{
// do some work and start th1T()
}
static void th1T()
{
while (true)
{
var ping = new Ping();
ping.Send(IP);
}
}
Here you'll be able to reach IP even if th1T is running on a different thread. There are some other options as well though, like injecting the IP into th1T when the thread is started. To do that you'd have to change the signature of th1T to this:
static void th1T(object data)
and you'd have to change the code a little:
static void th1T(object data)
{
while (true)
{
var ping = new Ping();
ping.Send(data as string);
}
}
You could then start that on another thread like this:
Thread newThread = new Thread(th1T);
newThread.Start(IP);
Threading is very much a subjective subject. If the value you're referencing from another thread is being read only, like in your example, and it's only set once by the controller (the class starting the work), then it's absolutely valid to share the variable between threads. Many however will argue to their death on this.
We can only speak in generalities in respect to this issue. For example, in general it's more appropriate to inject the value to avoid race conditions and dead locks. But again, that would really depend on what you're doing with the value. You can't inject the value if you're reading a flag from one thread that's set by another. In that case you have to safely synchronize the value.
There's no need to continue because as you see the rabbit hole only gets deeper.
You should refactor your method that pings to accept a string as a parameter:
static void th1T(string IP)
{
while (true)
{
var ping = new Ping();
ping.Send(IP);
}
}
And when you call the method, pass in your IP.
What you're wanting to do amounts to a global variable, which is generally not a good idea.
Another approach you could use is a static class to store the value:
public static class Values
{
string IP { get; set; }
}
And in your method:
static void th1T()
{
while (true)
{
var ping = new Ping();
ping.Send(Values.IP);
}
}
I want to add that there are several issues that could arise from this approach. It is probably not a best practice to do it this way.
You haven't shown how you are starting the thread but in all cases you have the possibility to send the string as parameter to the thread. For example if you are manually spawning a new Thread you could pass it as parameter to the Start method:
static void Main(string[] args)
{
string IP = "127.0.0.1"
Thread t = new Thread(th1T);
t.Start(IP);
}
static void th1T(object value)
{
// The value parameter will contain the IP here
string ip = (string)value;
while (true)
{
var ping = new Ping();
ping.Send(ip);
}
}
Notice how the th1T method now takes an object parameter that you could cast back to the value being passed. In this example we have passed a simple string value but you could pass arbitrary complex objects.
If you are using Tasks you also have the possibility to pass parameters:
static void Main(string[] args)
{
string IP = "127.0.0.1"
Task.Factory.StartNew(th1T, IP);
}
static void th1T(object value)
{
// The value parameter will contain the IP here
string ip = (string)value;
while (true)
{
var ping = new Ping();
ping.Send(ip);
}
}

Threaded network listener with return values

I'm currently trying to accomplish a project, which listens multiple ports and recieves incoming data.
DeviceListener class:
-I have a method called PortListener. It take two parameters whic are IP and Port addresses. It continously listens a specific port for incoming data.
-The other method is called StartListen which runs the PortListener in a thread.
Main program:
-It gets the port list and starts PortListener for each port using StartListen method.
Psuedo Like Code:
class DeviceListener()
{
private string PortListener(string ip, int port)
{
//listen ip and port.
//wait for data.
//recieve and return data.
RecieveData();
string data = recieved data;
return data;
}
public void StartListen(string ip, int port)
{
//start PortListener in a thread
Thread t = new Thread (() => PortListener(ip,port));
t.Start();
}
}
void Main()
{
ip = ip adress;
List portlist;
foreach (port in portlist)
{
string data = DeviceListener.StartListen(ip, port);
}
}
My problem is I just can't return the recieved data to my Main program.
Is there a way to get recieved datas for each PortListener thread?
You can do the following -
Add a queue of the data type you wish to receive. Best use the synchronized versions or create your own, depends on the .Net. See http://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx. Add each new stuff you get into the queue and make the queue public so other classes could access it. Other threads that wish to access incoming data can read can read from the queue and block if the queue is empty or poll by periodically checking if there are items present.
Another option is to use events (http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx) Your class can expose an event with the relevant data present and invoke it upon data arrival. Other classes will register and will get notified of new incoming data.
The first option is better if you have a single reading entity, the second is better if multiple entities are interested in the data.
I solved the problem by using a delegate method.
class DeviceListener()
{
public delegate void PassData(string str);
public PassData passdata;
private void PortListener(string ip, int port)
{
//listen ip and port.
//wait for data.
//recieve and return data.
RecieveData();
string data = recieved data;
passdata(data);
}
public void StartListen(string ip, int port)
{
//start PortListener in a thread
Thread t = new Thread (() => PortListener(ip,port));
t.Start();
}
}
void Main()
{
DeviceListener.passdata = new DeviceListener.PassData(Some_Function);
ip = ip adress;
List portlist;
foreach (port in portlist)
{
DeviceListener.StartListen(ip, port);
}
private void Some_Function(string data)
{
//do something with returned string.
}
}

Categories

Resources