This question is basically the same as 1 but instead Grpc.Core I would use the more up to date library Grpc.Net.Client. The Channel class here has neither a property "State" nor a ConnectAsync() method nor any other method to detect the current connection state. My goal is to write a Server and a Client application where the startup order ist arbitrary, i.e. If the Client is started before the Server it shall wait until the Server and therefore the connection becomes ready.
Related
Existing scenario is explained below.
Our application is running on Client Server architecture; Client is developed with VC++ and Server is developed with C#.
On the Server side there are two exe's running (myServer1.exe -Windows service based, and myServer2.exe -Windows application). myServer2.exe is communicating to myServer1.exe through TCP socket connection.On the Client side, an exe (myApp1.exe -Windows Service based) runs another exe based on user sessions present in the machine (myUser.exe for all user sessions). Every myUser.exe instances are communicating to myApp1.exe through PIPE communication. And myApp1.exe is also communicating to myServer1.exe through another TCP communication.
New scenario.
We are now creating a TCP socket in listening mode in myServer2.exe (Server application -C#). myUser.exe (Client application -VC++) is trying to connect to myServer2.exe through a TCP connection by using CAsyncSocket. But the framework calls (OnConnect, OnReceive and OnClose) are not happening.
Socket creation- Create(0,SOCK_STREAM); // CAyncSocket
Socket connection- Connect("ServerIP", "ServerPort"); // CAsyncSocket
Note: when we move the socket creation and connection functionalities into Windows service based exe (myApp1.exe), the connection works fine, OnConnect OnReceive and OnClose are happening.
Why framework call to OnConnect is not happening in myUser.exe while in myApp1.exe is?
Your OnConnect method is not called because probably you don't have the message loop in myUser.exe while you have it in myApp.exe.
Error code 10035 is WSAEWOULDBLOCK and it' normal for your case, from MSDN:
It is normal for WSAEWOULDBLOCK to be reported as the result from
calling connect on a nonblocking SOCK_STREAM socket, since some time
must elapse for the connection to be established.
So don't worry about it. If you have a message loop, after your Connect call, the OnConnect method will finally be called at a certain time with a successful result or with an error code.
See also codeproject and SO
I have two console applications, A and B.
The application A was created for test purposes and works as expected.
The application B does not work although it is basically a copy-paste of A's code:
System.Console.Write("User Name: ");
string username = System.Console.ReadLine();
System.Console.Write("Password: ");
string password = ConsoleReadPassword();
System.Console.WriteLine();
//user and password required because I am also a privileged user
//(member of mqm group)
MQEnvironment.UserId = username;
MQEnvironment.Password = password;
//for application B this line throws exception with code 2538
var queueManager = new MQQueueManager("TEST.QUEUE.MANAGER", "CLIENT.CONN.CHANNEL", "localhost(1414)");
Error code 2538 means "Host not available" which is weird because application A has no problems connecting to the same host.
This is how the MQ Server looks in MQ Explorer:
Queue managers:
Queues:
Listeners:
Channels:
Two server channels
Channel auth records:
Default channel authentication record which prevents MQ admins from connecting to queue managers. It was slightly modified (added ~ prefix) so now it does not block anyone.
The MQ Server and applications are running on the same machine so imho network problems are excluded.
The queue manager error log does not report any errors but the general error log looks like this:
08/02/2016 15:15:23 - Process(13720.10) User([username])
Program(B.EXE) AMQ9202: Remote host 'localhost(1414)' not
available, retry later.
EXPLANATION: The attempt to allocate a conversation using TCP/IP to
host 'localhost(1414)' for channel (Exception) was not successful.
However the error may be a transitory one and it may be possible to
successfully allocate a TCP/IP conversation later.
For both application I use the same version of amqmdnet.dll: 8.0.0.4
Both programs A and B have the same target framework: 4.5
While testing I didn't tried to run the both applications in the same time and I checked in MQ Explorer if the channel is free (Inactive).
I also tried to change the name of resulting assemblies but with no effect.
Does anyone know what could cause application B to be unable to connect?
When using the hostname localhost networking is still involved, it just all happens inside the one machine. If application A is running in the same machine as your queue manager then having application A connect using the connection name localhost(1414) will certainly work but it is not necessary to make the connection like this (i.e. using TCP/IP) you could instead make a local bindings connection.
On the other hand, if you are using TCP/IP because application B is running on a different machine to where the queue manager is running, then using localhost(1414) will not work because localhost on one machine does not connect to localhost on another machine. You should change what is specified in the application's connection name from localhost(1414) to use the IP address (or hostname) of the queue manager's machine (followed as before with the port number).
Although I was unable to find the cause of the problem the solution was to simply
delete and re-create the project.
This is what I tried before and what led me to this action:
In B I removed and then added back the reference to amqmdnet.dll - not working
I created yet another project (let's call it C): console application, same code - working
I renamed* the C project with the same name as B - still working
*The name of the non-working project contained a dot so I thought that this could cause the problem - it was not the case.
I am building a c#/wpf project.
It's architecture is this:
A console application which will be on a virtual machine (or my home computer) that will be the server side.
A wpf application that will be the client app.
Now my problem is this - I want the server to be able to send changes to the clients. If for example I have a change for client ABC, I want the server to know how to call a service on the clients computer.
The problem is, that I don't know how the server will call the clients.
A small example in case I didn't explain it well:
The server is on computer 1, and there are two clients, on computers 2 and 3.
Client 2 has a Toyota car and client 3 has a BMW car.
The server on computer 1 wants to tell client 2 that it has a new car, an Avenger.
How do I keep track and call services on the clients?
I thought of saving their ip address (from calling ipconfig from the cmd) in the DB - but isn't that based on the WI-FI/network they are connected to?
Thanks for any help!
You could try implementing SignalR. It is a great library that uses web sockets to push data to clients.
Edit:
SignalR can help you solve your problem by allowing you to set up Hubs on your console app (server) that WPF application (clients) can connect to. When the clients start up you will register them with a specified Hub. When something changes on the server, you can push from the server Hub to the client. The client will receive the information from the server and allow you to handle it as you see fit.
Rough mockup of some code:
namepsace Server{}
public class YourHub : Hub {
public void SomeHubMethod(string userName) {
//clientMethodToCall is a method in the WPF application that
//will be called. Client needs to be registered to hub first.
Clients.User(userName).clientMethodToCall("This is a test.");
//One issue you may face is mapping client connections.
//There are a couple different ways/methodologies to do this.
//Just figure what will work best for you.
}
}
}
namespace Client{
public class HubService{
public IHubProxy CreateHubProxy(){
var hubConnection = new HubConnection("http://serverAddress:serverPort/");
IHubProxy yourHubProxy = hubConnection.CreateHubProxy("YourHub");
return yourHubProxy;
}
}
}
Then in your WPF window:
var hubService = new HubService();
var yourHubProxy = hubService.CreateHubProxy();
yourHubProxy.Start().Wait();
yourHubProxy.On("clientMethodToCall", () => DoSometingWithServerData());
You need to create some kind of subscription model for the clients to the server to handle a Publish-Subscribe channel (see http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html). The basic architecture is this:
Client sends a request to the messaging channel to register itself as a subscriber to a certain kind of message/event/etc.
Server sends messages to the channel to be delivered to subscribers to that message.
There are many ways to handle this. You could use some of the Azure services (like Event hub, or Topic) if you don't want to reinvent the wheel here. You could also have your server application track all of these things (updates to IP addresses, updates to subscription interest, making sure that messages don't get sent more than once; taking care of message durability [making sure messages get delivered even if the client is offline when the message gets created]).
In general, whatever solution you choose is plagued with a common problem - clients hide behind firewalls and have dynamic IP addresses. This makes it difficult (I've heard of technologies claiming to overcome this but haven't seen any in action) for a server to push to a client.
In reality, the client talks and the server listens and response. However, you can use this approach to simulate a push by;
1. polling (the client periodically asks for information)
2. long polling (the client asks for information and the server holds onto the request until information arrives or a timeout occurs)
3. sockets (the client requests server connection that is used for bi-directional communication for a period of time).
Knowing those terms, your next choice is to write your own or use a third-party service (azure, amazon, other) to deliver messages for you. I personally like long polling because it is easy to implement. In my application, I have the following setup.
A web API server on Azure with and endpoint that listens for message requests
A simple loop inside the server code that checks the database for new messages every 100ms.
A client that calls the API, handling the response.
As mentioned, there are many ways to do this. In your particular case, one way would be as follows.
Client A calls server API to listen for message
Server holds onto call, waiting for new message entry in database
Client B calls server API to post new message
Server saves message to database
Server instance from step 2 sees new message
Server returns message to Client A.
Also, the message doesn't have to be stored in a database - it just depends on your needs.
Sounds like you want to track users à la https://www.simple-talk.com/dotnet/asp.net/tracking-online-users-with-signalr/ , but in a desktop app in the sense of http://www.codeproject.com/Articles/804770/Implementing-SignalR-in-Desktop-Applications or damienbod.wordpress.com/2013/11/20/signalr-a-complete-wpf-client-using-mvvm/ .
I run my application on a network and in some cases the client lost connection to the server. After this time, when I wanted to send a message to the server I receive the following error: Operation not allowed on non-connected sockets (something like this).
I thought to create an event for object type TcpClient and when tcp_obj.Connected = false to call a function to discontinue execution of the current code. How could I do this?
Or giving me other suggestios.
Thanks.
I know at least from socket programming in Java that when a client loses connection to the server, the server does not and can not know about it. You need a heartbeat of some sort to detect the early disconnection.
We often use a heartbeat in our client/server applications to detect early disconnections and log them on the server. This way the server can close the associated socket and release the connection back to the pool.
Simply send a command to the client periodically and wait for a response. If no response is garnered within a timeout assume disconnect and close streams.
I would simply first check your connection object to ensure you are connected, prior to attempting to send the message. Also make sure that you are putting your send-logic inside of a try-catch, so that if you do happen to get disconnected mid transmission, you'll be able to resume without blowing your application apart.
Psuedo-Code:
private void SendMessage(string message, Socket socket)
{
if(socket.connectionState = States.Connected)
{
try{
// Attempt to Send
}
catch(SocketException Ex)
{
// Disconenct, Additional Cleanup Etc.
}
}
}
If you are in C#, prior to your connection state changing, you will have a socket disconnected event fire, prior to your connection state changing. Make sure you tie this event up as soon as your socket connects.
Can we know why you use TCP sockets? Is for calling a tcp device o server code?
I recommend you if is for calling a .net server app use Windows Communication Foudation. It is simple to expose services by net.tcp, http, etc.
Regards,
Actually this is a very old problem,
If I understand your question correctly you need a way to know whether you're application is still connected to the server or vice versa.
If so then a workaround is to have a UDP connection just to check the connectivity (overhead I know, but its much better then polling on Connected state), you could check just before you send you're data.
Since UDP is not Connection oriented you don't need to be connected when you send the data
We have a TIBCO EMS solution that uses built-in server failover in a 2-4 server environment. If the TIBCO admins fail-over services from one EMS server to another, connections are supposed to be transfered to the new server automatically at the EMS service level. For our C# applications using the EMS service, this is not happening - our user connections are not being transfered to the new server after failover and we're not sure why.
Our application connection to EMS at startup only so if the TIBCO admins failover after users have started our application, they users need to restart the app in order to reconnect to the new server (our EMS connection uses a server string including all 4 production EMS servers - if the first attempt fails, it moves to the next server in the string and tries again).
I'm looking for an automated approach that will attempt to reconnect to EMS periodically if it detects that the connection is dead but I'm not sure how best to do that.
Any ideas? We are using TIBCO.EMS.dll version 4.4.2 and .Net 2.x (SmartClient app)
Any help would be appreciated.
First off, yes, I am answering my own question. Its important to note, however, that without ajmastrean, I would be nowhere. thank you so much!
ONE:
ConnectionFactory.SetReconnAttemptCount, SetReconnAttemptDelay, SetReconnAttemptTimeout should be set appropriately. I think the default values re-try too quickly (on the order of 1/2 second between retries). Our EMS servers can take a long time to failover because of network storage, etc - so 5 retries at 1/2s intervals is nowhere near long enough.
TWO:
I believe its important to enable the client-server and server-client heartbeats. Wasn't able to verify but without those in place, the client might not get the notification that the server is offline or switching in failover mode. This, of course, is a server side setting for EMS.
THREE:
you can watch for failover event by setting Tibems.SetExceptionOnFTSwitch(true); and then wiring up a exception event handler. When in a single-server environment, you will see a "Connection has been terminated" message. However, if you are in a fault-tolerant multi-server environment, you will see this: "Connection has performed fault-tolerant switch to ". You don't strictly need this notification, but it can be useful (especially in testing).
FOUR:
Apparently not clear in the EMS documentation, connection reconnect will NOT work in a single-server environment. You need to be in a multi-server, fault tolerant environment. There is a trick, however. You can put the same server in the connection list twice - strange I know, but it works and it enables the built-in reconnect logic to work.
some code:
private void initEMS()
{
Tibems.SetExceptionOnFTSwitch(true);
_ConnectionFactory = new TIBCO.EMS.TopicConnectionFactory(<server>);
_ConnectionFactory.SetReconnAttemptCount(30); // 30retries
_ConnectionFactory.SetReconnAttemptDelay(120000); // 2minutes
_ConnectionFactory.SetReconnAttemptTimeout(2000); // 2seconds
_Connection = _ConnectionFactory.CreateTopicConnectionM(<username>, <password>);
_Connection.ExceptionHandler += new EMSExceptionHandler(_Connection_ExceptionHandler);
}
private void _Connection_ExceptionHandler(object sender, EMSExceptionEventArgs args)
{
EMSException e = args.Exception;
// args.Exception = "Connection has been terminated" -- single server failure
// args.Exception = "Connection has performed fault-tolerant switch to <server url>" -- fault-tolerant multi-server
MessageBox.Show(e.ToString());
}
This post should sum up my current comments and explain my approach in more detail...
The TIBCO 'ConnectionFactory' and 'Connection' types are heavyweight, thread-safe types. TIBCO suggests that you maintain the use of one ConnectionFactory (per server configured factory) and one Connection per factory.
The server also appears to be responsible for in-place 'Connection' failover and re-connection, so let's confirm it's doing its job and then lean on that feature.
Creating a client side solution is going to be slightly more involved than fixing a server or client setup problem. All sessions you have created from a failed connection need to be re-created (not to mention producers, consumers, and destinations). There are no "reconnect" or "refresh" methods on either type. The sessions do not maintain a reference to their parent connection either.
You will have to manage a lookup of connection/session objects and go nuts re-initializing everyone! or implement some sort of session failure event handler that can get the new connection and reconnect them.
So, for now, let's dig in and see if the client is setup to receive failover notification (tib ems users guide pg 292). And make sure the raised exception is caught, contains the failover URL, and is being handled properly.
Client applications may receive notification of a failover by setting the tibco.tibjms.ft.switch.exception system property
Perhaps the library needs that to work?