I am trying to make a single application that is both a Client and Server using SignalR in .NET. The end goal is to integrate it with our existing product, which requires to be both a client and server as one computer acts as both, while the other computers are all clients.
Full source code on GitHub.
In the Client startup code, which is run after the Server startup code has completed, the following code is run:
m_hubConnection = new HubConnection( "http://localhost:8080/" );
m_myHubProxy = m_hubConnection.CreateHubProxy( nameof( ServerHub ) );
m_myHubProxy.On<string, string>( nameof( ServerHub.BroadCastMessage ), ( name, message ) => OnMessageReceived( name, message ) );
m_hubConnection.Closed += OnClosed;
m_hubConnection.Error += OnErrorReceived;
await m_hubConnection.Start(new WebSocketTransport());
await SendMessage( "Startup", "Sending from same thread as connection established" );
The OnClosed callback is called almost right away, so the connection closes immediately upon starting.
The OnErrorReceived callback is never called, so it does not close due to any obvious error
The Start method hangs and never calls back
The SendMessage method is never hit
Ideally, I want the connection to open, stay open, have that SendMessage be hit, send a message to the Hub, and have that broadcast the same message back to the client.
Any ideas on what's going wrong?
Fixed it, insanely silly mistake. I just switched from port 8080 to 8089. I guess something else is using port 8080, but regardless, switching both the client and server side to port 8089 fixed it.
Related
I have ZKTeco Biometrics device which is connected with a C# windows application using This tutorial (C# ZKTeco Biometric Device Getting Started).
It is working fine but after sometime, my application becoming failed to ping the device. As below code suggested, I am trying to ping the device after every 25 seconds.
private void TimerCheckPingAndCloseAttendanceForm() {
timerCheckPingAndCloseAttendanceForm = new Timer();
timerCheckPingAndCloseAttendanceForm.Tick += new EventHandler(CheckPingAndCloseAttendanceForm);
timerCheckPingAndCloseAttendanceForm.Interval = 25000;//25 seconds.
timerCheckPingAndCloseAttendanceForm.Start();
}
private void CheckPingAndCloseAttendanceForm(object sender, EventArgs e) {
string ipAddress = tbxDeviceIP.Text.Trim();
if (UniversalStatic.PingTheDevice(ipAddress) == false) {
//CloseAttendaceListForm();
IsDeviceConnected = false;
string infoString = "Application started on " + applicationStartDateTime.ToString() + " and ping failed on " + DateTime.Now.ToString() + " then, app closed while device ip is "+ ipAddress;
File.AppendAllText("ConnectionLog.txt", infoString + Environment.NewLine);
Application.Exit();
//timerCheckPingAndCloseAttendanceForm.Tick -= new EventHandler(CheckPingAndCloseAttendanceForm);
}
}
And when I am trying to ping the command from cmd the device show destination host is unreachable. But whenever I restart the device, the ping working fine. I don't know where is the problem? Either the network problem or its coding issue?
Note: I am doing a ping on regular time interval, because on Disconnected Event is not working. I am assuming ping failed meaning is the device has disconnected with the application.
First of all : Thank you for going through my article
You are doing it the wrong way.
Trying to ping the device after every 25 seconds is unnecessary.
The only job of the UniversalStatic.PingTheDevice method is to check if the device is presumably active, the first time you connect with the device.
If you want to check the status of the device i.e IsDeviceConnected, All you need to do is register to the device OnDisConnected event provided by the SDK.
It seems the code here at line number 57 has already done the OnDisConnected event registration for you.
All you need to do now is set your IsDeviceConnected to false when the objCZKEM_OnDisConnected method in the ZkemClient.cs class is called upon by the device itself.
Sample snippet :
In the ZkemClient.cs class file, between line number 81-84
void objCZKEM_OnDisConnected()
{
IsDeviceConnected = false; // <-- Add this line
}
Now, Every time you try to make a call to the device, All you need to do is check for the value of your IsDeviceConnected.
Not having the actual code and the hardware setup, this answer is a bit of a shot in the dark, but here goes …
Since it works initially, this is not a hardware configuration or network configuration issue. Yet it says that after a while the destination (reader) becomes unavailable. This is probably not a network keepalive issue because you are pinging every 25 sec. Looking at the code that you referenced, it shows opening a connection and hooking up callbacks, and making a call to a hardware feature.
My guess would be maybe you are opening the connection each ping and not closing the connection, then after a number of attempts the hardware jams because there are too many open connections. Just a guess. If this is the problem then to fix it, either close the connection or, better, keep the connection open and re-use it.
Alternative possibility would be that the router(s) between your code and the device are detecting too many pings and blocking the connection as a possible DOS attack. If this is the problem then to fix it, configure the router to allow the traffic.
This sounds like the device misbehaving. The error "destination host is unreachable" corresponds to an ICMP packet, same type of packet as ping but different job, being sent by your router saying "I have no idea which device has that IP". This normally happens when the device stop responding to ARP, which basically asks "who has this IP?" and expects a machine to respond "I have it" with its MAC address. The router constantly refreshes its ARP table, forgetting old values.
So when you boot the device it is 'happy', responding to ARP and responding to pings; however, something happens and it at least stops responding to ARP (probably something more wrong with it). Depending on its architecture it could be loaded down doing other stuff and unable to respond, or it could just be locked up.
Try slowing down other actions to the device (if your polling it for information other than ping, do it slower) and also see if you can get status from the device via another output (does it have a uart?).
OPTION 1
Since that restarting the device fixes your problem for a period of time, check that the IP that you are using is not in use on another device/computer/element_of_the_network.
ZKTeco devices come with the IP 192.168.1.201 configured by default. Configure a different static IP and avoid using DHCP (it´s well known that using DHCP in ZKTeco devices isn´t a good choice since they don´t refresh automatically the IP after rebooting the system or any network change).
Make sure that the IP is not in use and that nobody else will use it.
OPTION 2
Another thing that It may be the cause of your problem, is that you are using zkemkeeper in a different part of your application (or into a different application) and you are not closing the oppened connections properly... That may be blocking all network activity from the device. To close the connection just make sure that you call this sdk method after performing all the necessary actions:
sdk.Disconnect();
It looks like a code issue. While investigating UniversalStatic.PingTheDevice(ipAddress), its found that its calling System.Net.NetworkInformation.Ping.Send setting DontFragment = true. Reference: https://github.com/zaagan/BioMetrix/blob/master/BioMetrixCore/Utilities/UniversalStatic.cs#LC51. The timeout for the ping is set to 120 milli seconds. This tries to send 32 bytes of data to the given IP.
Following is the snippet taken from https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.ping.send?view=netframework-4.7.2 would answer the root-cause of your issue
If the DontFragment property is true and the total packet size exceeds the maximum packet size that can be transmitted by one of the routing nodes between the local and remote computers, the ICMP echo request fails. When this happens, the Status is set to PacketTooBig.
So when you restart your device, possibly, the data travelling on the network gets lost. Hence it started working till the packets reaching its limit.
Few suggestions:
Try calling System.Net.NetworkInformation.Ping.Dispose in PingTheDevice before returns
Increase the timeout from 120 milliseconds to seconds.
Increase the timerCheckPingAndCloseAttendanceForm.Interval to 1 min.
Check the return code of the System.Net.NetworkInformation.Ping.Send and find the associated failure meaning
Please share your findings if the above suggestions do not help you finding the root-cause.
you try this code for ping the device,
try
{
IPAddress ipAddress = IPAddress.Parse(ipAdd);
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(ipAddress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
return true;
else
{
return false;
}
}
catch (Exception)
{
return false;
}
Thanks.
I'm working on a .NET web app using SignalR with the hub class similar to the example class below:
public class ContosoChatHub : Hub
{
public override Task OnConnected()
{
// Add your own code here.
// For example: in a chat application, record the association between
// the current connection ID and user name, and mark the user as online.
// After the code in this method completes, the client is informed that
// the connection is established; for example, in a JavaScript client,
// the start().done callback is executed.
return base.OnConnected();
}
public override Task OnDisconnected()
{
// Add your own code here.
// For example: in a chat application, mark the user as offline,
// delete the association between the current connection id and user name.
return base.OnDisconnected();
}
public override Task OnReconnected()
{
// Add your own code here.
// For example: in a chat application, you might have marked the
// user as offline after a period of inactivity; in that case
// mark the user as online again.
return base.OnReconnected();
}
}
More specific, my web app serves as hub for connecting tablets. when i close the app on the tablet it does not trigger instantly the OnDisconnected task, taking up to 20 seconds or more (server tries to reconnect with the client).
My question is, which method should I use in order to detect the connection loss as soon as it happens or, is there a connection state handler that triggers when the connection is lost?
In order to prevent the data loss (considering a tablet online when in fact it's not) I really need to handle the disconnecting event.
Any help is much appreciated!
Later edit:
I've also included the following lines in the Global.asax file
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(6);
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(2);
in the Application Start method. The values seem to be saved, as seen in debug and actually reduce the time by half, from 20-30 to 12-14 seconds, but it's still not as close to 2-3 seconds.
You can detect the server disconnection from SignalR client:
$.connection.hub.disconnected(function () {
alert('Server has disconnected');
});
This is the official documentation when each method called:
When OnConnected, OnDisconnected, and OnReconnected are called
Each time a browser navigates to a new page, a new connection has to
be established, which means SignalR will execute the OnDisconnected
method followed by the OnConnected method. SignalR always creates a
new connection ID when a new connection is established.
The OnReconnected method is called when there has been a temporary
break in connectivity that SignalR can automatically recover from,
such as when a cable is temporarily disconnected and reconnected
before the connection times out. The OnDisconnected method is called
when the client is disconnected and SignalR can't automatically
reconnect, such as when a browser navigates to a new page. Therefore,
a possible sequence of events for a given client is OnConnected,
OnReconnected, OnDisconnected; or OnConnected, OnDisconnected. You
won't see the sequence OnConnected, OnDisconnected, OnReconnected for
a given connection.
The OnDisconnected method doesn't get called in some scenarios, such
as when a server goes down or the App Domain gets recycled. When
another server comes on line or the App Domain completes its recycle,
some clients may be able to reconnect and fire the OnReconnected
event.
I'm trying to build multiple client - one server structure. Each client makes connection to server and server maintains those connection.
Client have two thread(thread1, thread2) running asynchronously and sharing 1 socket to send, receive. Two thread each contain multiple send, receive function. For server to serve each client, it also have to make two client handler that share 1 socket.
I wanna have my server to create client handler routine(asynchronous task) only when their(each client) socket is ready-to-read to save resource. I'm trying to implement this feature using 'Socket.Select' method.
Here's my assumed implementation of server side select routine using code close to c#.
server.selectRoutine(){
while(!serverSocket.closed())
{
checkReadList client_connect_socket_list_copy=new ArrayList<Socket>(client_connect_socket_list) ;
Socket.Select(client_connect_socket_list_copy, null,null) ;
foreach(Socket s in client_connect_socket_list_copy)
{
client_connect_info info=client_connect_info_dict.Items[s] ;
if(!info.is_client_thread1_handler_active)
{
info.is_client_thread1_active=true ;
clServerEntranceHandler handler=new clServerEntranceHandler() ;
Task.Run(handler.run()) ;
}
if(!info.is_client_thread2_handler_active)
{
info.is_client_thread2_active=true ;
clServerExitHandler handler=new clServerExitHandler() ;
Task.Run(handler.run()) ;
}
}
Code Explanation
Client_connect_socket_list: contains currently connected clients
client_connect_info_dict: client connect info dictionary mapped for each socket as key.
client_connect_info: consist of (is_client_thread1_Handler_Active, is_client_thread2_Handler_Active)
Select only those sockets that are ready to be read after Socket.Select
Run handler for those sockets where handler is currently not made, info.is_client_thread1_Handler_Active=false. And set info.is_client_thread1_Handler_Active=true. This is because there will be multiple recv function inside already-made handler and they are in blocking mode. So when client sends message to server destined to recv function blocked in already-made handler, Socket.Select will also think this socket as ready-to-read and it will end up creating new handler. To avoid this, i need to check whether handler is active. After handler finishes, it will set info.is_client_thread1_Handler_Active= false inside. Same for client_thread2 handler.
I think i now have to synchronize this routine with each handler already made. For example, avoid situation like recv function inside handler P snatch message A inside message queue of handler P's socket after Socket.Select saw message A inside message queue. Then handler P will end and set info.is_Handler_Active=false. Then selectRoutine will create new handler again for message A already read by handler P and there goes trouble.
I wanna know whether there is serious problem with this scheme that i should not use it. And if there is, then i wanna know better ways to implement multiple client - one server with room for scaling.
I am trying to make an aSync connection to a server using TcpClient.BeginConnect, but am encountering some difficulties. This is my first time using Tcp so please bear with me.
The connection itself works fine when the server is running, i can send and receive messages without problem. However when I stop the server and try to connect to it, Tcp.BeginConnect will pretend it is actually connected to a server without returning an error, until i try to actually send data which will obviously fail.
When i use TcpClient.Connect() instead it'll return A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. when no connection is established after a few seconds, letting me know the connection failed.
Is there a way to get this same behaviour with TcpClient.BeginConnect? Or am I doing something wrong myself?
i looked around and found C# BeginConnect callback is fired when not connected which is somewhat similair and the answer was that EndConnect had to be called in the callback before the socket becomes usuable, but i'm already doing that.
my code:
public static void OpenTcpASyncConnection()
{
if (client == null)
{
client = new TcpClient();
IAsyncResult connection = client.BeginConnect(serverIp, serverPort, new AsyncCallback(ASyncCallBack), client);
bool succes = connection.AsyncWaitHandle.WaitOne();//returns true
if (!succes)
{
client.Close();
client.EndConnect(connection);
throw new Exception("TcpConnection::Failed to connect.");
}
else
{
Debug.LogFormat("TcpConnection::Connecting to {0} succeeded", serverIp);
}
}
else
{
Debug.Log("TcpConnection::Client already exists");
}
}
public static void ASyncCallBack(IAsyncResult ar)
{
Debug.Log("Pre EndConnect");
client.EndConnect(ar);
Debug.Log("Post EndConnect");//this never gets called?
}
the boolean succes is true even if the server is offline (or does this always return true as long as the operation finishes?), thus i assume it thinks it is actually connected, and the Debug.Log after client.EndConnect(ar) never gets called. Not a single error gets returned.
In summary; Am I forgetting something/doing something wrong? or is this expected behaviour?
Edit: language is C# with the .net 3.5 framework. It is ment for a Unity application though i'm not inheriting from monobehaviour for this. If you require any additional information I will try to provide this.
Kind regards and thanks for your time,
Remy.
I am trying to connect to an existing JMS queue with a .NET client.
I know the queue is working, I already browsed it using IBM MQ Explorer.
In the following code, the call to factory.CreateConnection keeps hanging - it does not jump to the next line, in does not show any error message. It even doesnt consume any CPU.
Are there any options that I should try to get it working (or at least make it show me an error message of any kind)?
private static IConnectionFactory GetConnectionFactory()
{
var factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
var cf = factoryFactory.CreateConnectionFactory();
cf.SetStringProperty(XMSC.WMQ_HOST_NAME, "server address");
cf.SetIntProperty(XMSC.WMQ_PORT, portnumber);
cf.SetStringProperty(XMSC.WMQ_CHANNEL, "channelname");
cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "queuemanager");
cf.SetIntProperty(XMSC.WMQ_BROKER_VERSION, XMSC.WMQ_BROKER_UNSPECIFIED);
return (cf);
}
The main method has the following:
var factory = GetConnectionFactory();
var connection = factory.CreateConnection("username", null);
I don't see any problem with your code, tested it with MQ v8 and works fine. I would suggest you to do:
1) XMS can run in unmanaged mode also. So change
cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
to
cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED)
and see if that helps.
2) When the call hangs, break into debug and see the call stack to determine the point of hang. It could be waiting on some system event if no CPU is being consumed.
3) Open a PMR with IBM.