I want to know how can I send request from server to client using GKSession?
The reference class for GKSession say the following:
- (void)connectToPeer:(NSString *)peerID withTimeout:(NSTimeInterval)timeout Parameters peerID The string that
identifies the peer to connect to.
timeout The amount of time to wait before canceling the connection
attempt.
Discussion
When your application is acting as a client, it calls this method to
connect to an available peer it discovered. When your application
calls this method, a request is transmitted to the remote peer, who
chooses whether to accept or reject the connection request.
What should I use if I am server?
As a server you make yourself available for client connections with
peer2peerSession.available = YES;
Here is an example of creating a GKSession instance as a server:
[[GKSession alloc] initWithSessionID:sessionID displayName:#"Chris" sessionMode : GKSessionModeServer];
Here is an example of how to create a GKSession as a client:
[[GKSession alloc] initWithSessionID:sessionID displayName:#"Angel" sessionMode : GKSessionModeClient];
GKSessionModePeer will create a GKSession instance that will both advertise itself as a server, and at the same time look for advertising servers (in other words act as a client searching for servers).
You then need to set a delegate for your GKSession object, after-which the delegate needs to implement the following delegate method:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState : (GKPeerConnectionState)state
Within the above method you will receive messages from the session that a device has become available, became unavailable, connected, etc.
To send a request:
[_session connectToPeer:peerID withTimeout:_session.disconnectTimeout];
To accept a request:
[_session acceptConnectionFromPeer:peerID error:&error];
There is a lot of code involved and the best tutorial for you to understand everything is located here: Simple Card Playing game using GKSession
Related
I'm using the Reachability class from apples demo projects to ping some servers pages. But no matter what I write in URL I always get ReachableViaWiFi.
Reachability* reachability = [Reachability reachabilityWithHostName:URL];
NetworkStatus netStatus = [reachability currentReachabilityStatus];
I'm connected to a Wifi, but I just want to check if some servers are available or not. (With the answer "NO" if I'm disconnected from the net).
Any suggestions please, even with others classes with the same goal.
Thanks
From the docs:
A remote host is considered reachable when a data packet, sent by an
application into the network stack, can leave the local device.
Reachability does not guarantee that the data packet will actually be
received by the host.
Edit: So, if there is a route available (whether the server is actually listening or not), it return that route's quality, in your case WiFi.
How about just sending your request and checking out the result?
As to your question for another library: Those questions are deemed off topic here.
Implementing an app with automatic connection between devices to exchange small bunch of data, using Multi-peer Connectivity framework and Nearby Services (both browser and advertiser).
I built a Session Manager handling all connections details. Its delegate is a View Controller in order to handle updates of UI when data are received.
The Session Manager builds:
A Service Advertiser, the delegate being the Session Manager
A Service Browser, the delegate being also the Session Manager
Launching the app on two devices (one under Xcode to get the logs, the other one stand alone), I receive a Found Peer message through Service Browser delegate corresponding method.
As stated in another message, I compare the displayName property of MCPeerID (both local and from received Peer) to decide whichever of both will send invitation, thus avoiding cross-invitations.
As stated on another message here, I have also added the "optional" MCSession delegate method - (void)session:didReceiveCertificate:fromPeer:certificateHandler:
However, delegate method (void)advertiser:didReceiveInvitationFromPeer:withContext:invitationHandler: of MCNearbyServiceAdvertiser is never called. There is only a NotConnected message received by the MCSession delegate method (void)session:peer:didChangeState:after the timeout setup in the invitePeer:toSession:withContext:timeout:method.
In the various options proposed:
Session is initialized with security nil and MCEncryptionNone;
discoveryInfo are nil;
context sent in the invitation is just a short string archived as NSData.
To troubleshoot:
I have checked that all items were existing (session and its delegate, advertiser and its delegate).
Service Browser and Advertiser are never stopped, as long as app is active.
I don't know where to look over now!
Make sure that the MCpeerID you use for your local peer is the same for both the discovery and invitation phases.
I had a structure with a separate session manager to the connect/transfer worker. I made the mistake of initialising a new MCpeerID in the worker to create a session prior to the invitation, resulting in the same behaviour.
Passing the MCpeerID and MCNearbyServiceBrowser to the worker to create the session and invite fixed the issue.
We have (Multiple)Clients-(One)Server architecture for poker desktop game. We are using callback Notifications using callback Channels.
But sometimes because of internet connection drops, that particualr client gets disconected from server and that particular's client's WCF channel is also gone to faluted state and his callback Channel which lies in server is also faluted.
Scenario :
That client is playing game, while internet connection drops, that game is stopped, still his game window remains open and when his/her internet connection gets back that client is dropped out from Server, but that player's game window still opens and that player can't do anything as his/her WCF channel is dropped out.
We want to close that particular client's window while he/she is dropped out from server and throwing 'CommunicationObjectAbortedException ' exception.
We can't use previous WCF channel's callback channel as it's in faluted state.
So we have tried to create new callbackChannel in server while dropping using below code :
OperationContext.Current.GetCallbackChannel();
but here Current is showing "NULL" as that player's WCF channel is aborted, so it's throwing an error that "Object reference not set to an instance of object".
So is there any solution to use aborted WCF channel's callback Channel or recover that WCF channel without reinitializing them or to call that client using new channel?
I'd try following:
On server side, when trying to communicate using faulted / aborted chanel - you'll failed.
Catch this failure, and remove its callback from the list (I suppose you manage some callback list).
On client side - when chanel Faulted / ... handled - try to re-open new chanel to server. When this new chenel will be open, on server side place this new callback back to the "valid callbacks" list.
I have a working server/client app using Distributed Objects in objective-c. What I am struggling with right now is making the app multi-threaded. So that more users can access the server at the same time.
Here is main function for the server. This is where I create the nsconnection object.
From my understanding, the way I should approach this is when a user tries to access the server, a new thread should be allocated for that particular call. Should the [conn runInNewThread] takes care of this ?
Any thoughts is appreciated...
Here is the code for the server.
int main (void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Transactions *trans = [Transactions new];
NSConnection *conn = [NSConnection defaultConnection];
[conn setRootObject: trans];
[conn runInNewThread];
if (![conn registerName:#"holycow"])
{
NSLog (#"Failed registering holycow.");
exit (1);
}
NSLog (#"waiting for connections...");
[[NSRunLoop currentRunLoop] run];
[pool release];
return 0;
}
In order to respond to client messages, the responding server object
must be set as the ’root object’ of an instance of the NSConnection
class, and this NSConnection must be registered with the network by
name.
So in case of Distributed object, single server object can handle multiple clients. or you can create more server object and divide your clients.
#Parag Bafna was right in his answer when I ran a test. However, I used a special kind of architecture in the server that may have aided in this. Take for instance a command that takes a long time to run on the server daemon. This can hang a server up a bit and make it much slower for connections to be processed. Here's my solution.
Have the client call an asynchronous class method using the oneway property. Let's call this runProcess.
Make runProcess do a popen() on the task and keep the PID as a global variable.
Then, make it use performSelectorInBackground to run a synchronous class method called readProcess in the background.
In readProcess, I use while(fgets(buff, sizeof(buff), ghPID)!=NULL) to read the previously established popen() output (note the global variable, ghPID) and append the latest line read into a global variable of recent lines read. This method runs as a background task, and the client has already disconnected from runProcess.
Now have the client connect to a synchronous class method called getProcessData. This should then take the global variable of recent lines read and return it back. Since that doesn't take very long to do, the client disconnects from that class method pretty quickly.
The client can then poll that data until it knows it's done. To aid with that, you can create a synchronous method called isProcessRunning that can check on a global boolean variable on the server daemon called gbRunning and return true/false. Of course, though, it will be up to you to flip that variable in the server daemon true/false in the various class methods when the server is busy running a popen() task.
By doing it this way, your server daemon can respond to concurrent requests much faster.
An additional tip would be to use a kill file or other mechanism (shared memory? SIGHUP?) so that if you're in a while loop and you want that process to stop, you can just drop a kill file somewhere in /tmp for instance and the process will use pclose to kill it and then erase the kill file. I also do this before starting a process if I want to ensure only one particular process runs at a time from that server daemon.
i'm currently trying to set up something like this:
a server side windows wcf service hangs out and listens via tcp for connections from a client side windows service.
when a connection is received (the client calls the CheckIn method on the service) the service obtains a callback channel via OperationContext.Current.GetCallbackChannel<T>
this channel is stored in a collection along with a unique key (specifically, i store the callback interface, the channel, and the key in a List<ClientConnection> where each of those is a property)
calls should now be able to be passed to that client service based on said unique key
this works at first, but after a while stops -- i'm no longer able to pass calls to the client. i'm assuming it's because the connection has been dropped internally and i'm trying to work with a dead connection.
that in mind, i've got the following questions:
how do i tell wcf i want to keep those tcp connections indefinitely (or for as long as possible)?
how do i check, from the client side, whether or not my connection to the server is still valid so i can drop it and check in with the server again if my connection is fried?
i can think of gimpy solutions, but I'm hoping someone here will tell me the RIGHT way.
When you establish the connection from the client, you should set two timeout values in your tcp binding (the binding that you will pass to ClientBase<> or DuplexClientBase<>):
NetTcpBinding binding = new NetTcpBinding();
binding.ReceiveTimeout = TimeSpan.FromHours(20f);
binding.ReliableSession.InactivityTimeout = TimeSpan.FromHours(20f);
My sample uses 20 hours for timeout, you can use whatever value makes sense for you. Then WCF will attempt to keep your client and server connected for this period of time. The default is relatively brief (perhaps 5 minutes?) and could explain why your connection is dropped.
Whenever there is a communication problem between the client and server (including WCF itself dropping the channel), WCF will raise a Faulted event in the client, which you can handle to do whatever you feel appropriate. In my project, I cast my DuplexClientBase<> derived object to ICommunicationObject to get a hold of the Faulted event and forward it to an event called OnFaulted exposed in my class:
ICommunicationObject communicationObject = this as ICommunicationObject;
communicationObject.Faulted +=
new EventHandler((sender, e) => { OnFaulted(sender, e); });
In the above code snippet, this is an instance of my WCF client type, which in my case is derived from DuplexClientBase<>. What you do in this event is specific to your application. In my case, the application is a non-critical UI, so if there is a WCF fault I simply display a message box to the end-user and shut down the app - it'd be a nice world if it were always this easy!