I have written a Singleton Class using GCDAsyncsocket Library to establish connection with any other device having same service using Bonjour.
On one device I am using its Method "startPublishing" to make it a Host(Server), from the Application on another Device(Client) I am calling "StartBrowsing" to find out the available Devices in Network. When user selects any of service in that Network I am calling method "initConnectionWithService", that initiate Connection flow by resolving address of NetService to connect.
BonjourUtilClass.h
#interface BonjourUtilClass : NSObject<GCDAsyncSocketDelegate,NSNetServiceDelegate,NSNetServiceBrowserDelegate>{
NSNetService *netServiceToPublish;
GCDAsyncSocket *socketPub;
NSNetServiceBrowser *netServiceToBrowse;
GCDAsyncSocket *socketSub;
NSMutableArray *mutArrServices;
GCDAsyncSocket *socketConnected;
}
+(id)sharedInstance;
-(void)startPublishing;
-(void)startBrowsing;
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect;
-(void)disconnectWithCurrent;
#end
BonjourUtilClass.m
static BonjourUtilClass *sharedObject = nil;
#implementation BonjourUtilClass
+(id)sharedInstance{
if(!sharedObject){
sharedObject = [[BonjourUtilClass alloc]init];
}
return sharedObject;
}
#pragma mark - Browsing
-(void)startBrowsing{
if(mutArrServices){
[mutArrServices removeAllObjects];
}else{
mutArrServices = [NSMutableArray array];
}
netServiceToBrowse = [[NSNetServiceBrowser alloc]init];
netServiceToBrowse.delegate= self;
[netServiceToBrowse searchForServicesOfType:#"_mrug._tcp" inDomain:#"local."];
}
-(void)stopBrowsing{
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices addObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices removeObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"Search browser Did STOP search..");
[self stopBrowsing];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict{
NSLog(#"Search browser Did not search..");
[self stopBrowsing];
}
#pragma mark - NetService Delegate
-(void)startPublishing{
socketPub = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *aError;
if([socketPub acceptOnPort:0 error:&aError]){
netServiceToPublish = [[NSNetService alloc]initWithDomain:#"local." type:#"_mrug._tcp" name:#"" port:socketPub.localPort];
netServiceToPublish.delegate =self;
[netServiceToPublish publish];
}else{
NSLog(#"Unable To Create Socket..");
}
}
//NetService Delegates
-(void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict{
NSLog(#"Failed To Publish : Domain=%# type=%# name=%# info=%#",sender.domain,sender.type,sender.name,errorDict);
}
-(void)netServiceDidPublish:(NSNetService *)sender{
NSLog(#"Service Published : Domain=%# type=%# name=%# port=%li",sender.domain,sender.type,sender.name,(long)sender.port);
}
//Resolving Address
- (void)netService:(NSNetService *)service didNotResolve:(NSDictionary *)errorDict {
[service setDelegate:nil];
}
- (void)netServiceDidResolveAddress:(NSNetService *)service {
// Connect With Service
if ([self connectWithService:service]){
NSLog(#"Did Connect with Service: domain(%#) type(%#) name(%#) port(%i)", [service domain], [service type], [service name], (int)[service port]);
} else {
NSLog(#"Unable to Connect with Service: domain(%#) type(%#) name(%#) port(%i)", [service domain], [service type], [service name], (int)[service port]);
}
}
#pragma mark - GCDSocket delegates
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(#"Accepted new Socket: HOST : %# , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
NSLog(#"Socket DisConnected %s,%#,%#",__PRETTY_FUNCTION__, sock,err);
if(socketPub == sock){
socketPub.delegate = nil;
socketPub = nil;
}else if (socketConnected == sock){
socketConnected.delegate=nil;
socketConnected = nil;
}
}
- (void)socket:(GCDAsyncSocket *)socket didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Socket Did Connect to Host: %# Port: %hu", host, port);
// Start Reading
[socket readDataToLength:sizeof(uint64_t) withTimeout:-1.0 tag:0];
}
#pragma mark - Connection Methods
-(void)disconnectWithCurrent{
if(socketConnected){
[socketConnected disconnect];
socketConnected.delegate = nil;
socketConnected = nil;
}
}
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect{
// Resolve Service
[netServiceToConnect setDelegate:self];
[netServiceToConnect resolveWithTimeout:30.0];
}
- (BOOL)connectWithService:(NSNetService *)service {
BOOL _isConnected = NO;
// Copy Service Addresses
NSArray *addresses = [[service addresses] mutableCopy];
if (!socketConnected || ![socketConnected isConnected]) {
// Initialize Socket
socketConnected = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
// Connect
while (!_isConnected && [addresses count]) {
NSData *address = [addresses objectAtIndex:0];
NSError *error = nil;
if ([socketConnected connectToAddress:address error:&error]) {
_isConnected = YES;
} else if (error) {
NSLog(#"Unable to connect to address. Error %# with user info %#.", error, [error userInfo]);
}
}
} else {
_isConnected = [socketConnected isConnected];
}
return _isConnected;
}
#end
But, On execution of above things very unexpected things happending, Device which is acting as Client is getting callback in didConnectedToHost and immediatly, another Callback is coming that is in didDisconnected
Logs on Client Device
2014-12-11 15:16:32.512 GCDSocketDemo[1419:71238] Did Connect with Service: domain(local.) type(_mrug._tcp.) name(ind506Bonjour) port(52026)
2014-12-11 15:16:32.659 GCDSocketDemo[1419:71238] Socket Did Connect to Host: 10.2.4.130 Port: 52026
2014-12-11 15:16:32.660 GCDSocketDemo[1419:71238] -[AppDelegate socketDidDisconnect:withError:],<GCDAsyncSocket: 0x7fa0a3533b90>,Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo=0x7fa0a3532f70 {NSLocalizedDescription=Socket closed by remote peer}
Logs On Server Device
2014-12-11 15:15:48.546 GCDSockrtMacDemo[1397:70851] Service Published : Domain=local. type=_mrug._tcp. name=ind506Bonjour port=52026
2014-12-11 15:16:32.585 GCDSockrtMacDemo[1397:70851] Accepted new Socket: HOST : 10.2.4.130 , CONNECTION PORT :52029
2014-12-11 15:16:32.613 GCDSockrtMacDemo[1397:70851] -[BonjourUtilClass socketDidDisconnect:withError:],(null),(null)
Comment of Paulw11 Helped me to find out the Solution. Actually I stored Socket on client side, but forgot to Store reference of new Socket getting in callback method "didAcceptNewSocket".
So the Method didAcceptNewSocket should be as below:
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(#"Accepted new Socket: HOST : %# , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
socketConnected = newSocket;
}
So that newSocket received in this method can be persist for further communication. In earlier case it was releasing at end of method.
Related
I'm hosting a service in a Mac application and connecting with an iOS app. While the iOS app will find the service, the service doesn't contain any addresses, so I can't connect a socket.
This is my hosting code on the Mac:
- (void)start {
queue = dispatch_queue_create("KeyboardServer", DISPATCH_QUEUE_CONCURRENT);
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:queue];
NSError *error = nil;
if ([socket acceptOnPort:0 error:&error]) {
service = [[NSNetService alloc] initWithDomain:#"local." type:#"_probonjore._tcp." name:#"TestServer" port:[socket localPort]];
service.delegate = self;
[service publish];
} else {
NSLog(#"Unable to create server");
}
}
This is the connecting code on iOS:
- (BOOL)connectToServer:(NSNetService *)service {
NSArray *addresses = service.addresses;
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:queue];
for (NSData *address in addresses) {
NSError *error;
if ([socket connectToAddress:address error:&error]) {
NSLog(#"Socket connected!");
return true;
}
}
return false;
}
The problem is, service.addresses is always empty and the loop instantly exits.
For anyone curious, I searched around and found a solution.
In the
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing
function, you need to:
Add the service to an array to stop the object being deallocated as soon as it goes out of scope
Set the delegate on the object so that you can respond to its address resolution
Call the function to make it resolve
Which looks like this:
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
NSLog(#"Found Service %#", [service name]);
[services addObject:service];
[service setDelegate:self];
[service resolveWithTimeout:5.0f];
}
You then want to implement
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
and
- (void)netServiceDidResolveAddress:(NSNetService *)service
To catch when the address either resolves or doesn't resolve.
Friends
i am working on a chat application where there a function in backend like
client.on('mjmChatAddUser', function(user, room)
{
// Guest
if(user == null)
user = mjmChatCreateGuestName();
// Convert special characters to HTML entities
user = htmlEntities(user);
room = htmlEntities(room);
client.username = user;
client.room = room;
mjmChatUsernames.push(user);
client.join(room);
client.emit('mjmChatStatusUser', 'you have joined to '+ room +' room');
client.broadcast.to(room).emit('mjmChatStatusUser', user +' has joined to this room');
client.emit('mjmChatRooms', room);
io.sockets.to(room).emit('mjmChatUsers', mjmChatGetUsersRoom(room));
});
Now from ios side , I want to use ScoketIO to call this function , I have made connection to server but not enable to call this function , this what i am doing , is it right way , please guide me
- (void) viewDidLoad
{
[super viewDidLoad];
// create socket.io client instance
socketIO = [[SocketIO alloc] initWithDelegate:self];
// you can update the resource name of the handshake URL
// see https://github.com/pkyeck/socket.IO-objc/pull/80
// [socketIO setResourceName:#"whatever"];
// if you want to use https instead of http
// socketIO.useSecure = YES;
// pass cookie(s) to handshake endpoint (e.g. for auth)
NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
#"localhost", NSHTTPCookieDomain,
#"/", NSHTTPCookiePath,
#"auth", NSHTTPCookieName,
#"56cdea636acdf132", NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
NSArray *cookies = [NSArray arrayWithObjects:cookie, nil];
socketIO.cookies = cookies;
// connect to the socket.io server that is running locally at port 3000
[socketIO connectToHost:#"MY SERVER" onPort:3000];
}
# pragma mark -
# pragma mark socket.IO-objc delegate methods
- (void) socketIODidConnect:(SocketIO *)socket
{
NSLog(#"socket.io connected.");
NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];
[dict2 setObject:#"demo1" forKey:#"user"];
[dict2 setObject:#"php" forKey:#"room"];
[socketIO sendEvent:#"mjmChatAddUser" withData:#{#"Abc":#"php"}];
}
- (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet
{
NSLog(#"didReceiveEvent()");
// test acknowledge
SocketIOCallback cb = ^(id argsData) {
NSDictionary *response = argsData;
// do something with response
NSLog(#"ack arrived: %#", response);
// test forced disconnect
[socketIO disconnectForced];
};
[socketIO sendMessage:#"hello back!" withAcknowledge:cb];
}
- (void) socketIO:(SocketIO *)socket onError:(NSError *)error
{
if ([error code] == SocketIOUnauthorized) {
NSLog(#"not authorized");
} else {
NSLog(#"onError() %#", error);
}
}
- (void) socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error
{
NSLog(#"socket.io disconnected. did error occur? %#", error);
}
The code below is intended to receive UDP multicast messages on 239.255.255.250 and simply NSLog the contents of the message.
If I address a message to the IP of the iOS device (i.e. from a terminal echo foo | nc -u 10.1.10.249 1900) the message is received and NSLog'd.
However, if I broadcast a message to the multicast address (echo bar | nc -u 239.255.255.250 1900), the message is not received.
No error messages are logged at start up.
Thoughts on where I'm going awry?
#import "ViewController.h"
#import "GCDAsyncUdpSocket.h"
#interface ViewController () {
GCDAsyncUdpSocket *udpSocket;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:1900 error:&error]) {
NSLog(#"Error starting server (bind): %#", error.description );
return;
}
if(![udpSocket joinMulticastGroup:#"239.255.255.250" error:&error] ) { //]onInterface:#"en0" error:&error]) {
NSLog(#"Error joining multicast group: %#",error.description);
return;
}
if (![udpSocket beginReceiving:&error]) {
[udpSocket close];
NSLog(#"Error starting server (recv): %#", error.description);
return;
}
NSLog(#"Udp server started on port %#:%hu", [udpSocket localHost_IPv4], [udpSocket localPort]);
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext {
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"message rec'd: %#:%hu %#\n", [udpSocket localHost_IPv4], [udpSocket localPort],msg);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
You're missing a key function that stumped me for a time, too.
[udpSocket enableBroadcast:YES error:&error];
This will allow you to send broadcast packets and receive broadcasted packets from your multicast group.
I'm using https://github.com/robbiehanson/XMPPFramework to connect to my own ejabberd server, but it always failed after negotiation.
here is the log I got:
2014-01-17 07:14:40.780 Chat[48246:70b] error: (null)
2014-01-17 07:14:40.789 Chat[48246:70b] xmppStreamWillConnect
2014-01-17 07:14:46.076 Chat[48246:70b] socketDidConnect
2014-01-17 07:14:46.077 Chat[48246:70b] xmppStreamDidStartNegotiation
2014-01-17 07:14:51.799 Chat[48246:70b] xmppStreamDidDisconnect: Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo=0x918d2e0 {NSLocalizedDescription=Socket closed by remote peer}
and here is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.stream = [[XMPPStream alloc] init];
self.stream.myJID = [XMPPJID jidWithString:#"test#gmail.com"];
self.stream.hostName = #"my host ip";
self.stream.hostPort = 5222;
[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
self.reconnect = [[XMPPReconnect alloc] init];
[self.reconnect activate:self.stream];
self.muc = [[XMPPMUC alloc] init];
[self.muc activate:self.stream];
NSError *error = nil;
if (![self.stream connectWithTimeout:XMPPStreamTimeoutNone error:&error]) {
NSLog(#"error: %#", error);
}
NSLog(#"error: %#", error);
}
- (void)xmppStreamWillConnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamWillConnect");
}
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
NSLog(#"socketDidConnect");
}
- (void)xmppStreamDidStartNegotiation:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidStartNegotiation");
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
NSLog(#"willSecureWithSettings: %#", settings);
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidSecure");
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidConnect");
NSError *error = nil;
[self.stream authenticateAnonymously:&error];
NSLog(#"authenticate: %#", error);
}
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidRegister");
}
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
{
NSLog(#"didNotRegister: %#", error);
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidAuthenticate");
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
NSLog(#"didNotAuthenticate: %#", error);
}
- (void)xmppStreamWasToldToDisconnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamWasToldToDisconnect");
}
- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender
{
NSLog(#"xmppStreamConnectDidTimeout");
}
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
NSLog(#"xmppStreamDidDisconnect: %#", error);
}
Check if the solution reported here https://github.com/robbiehanson/XMPPFramework/issues/131 solves your issue.
Generally when the server is closing the connection, you get this
error/ Two reasons when the server closes the connection:
You are not sending regular pings if the client idle.
You are logging in from some different client with the same credentials, and in the server settings have the setting:
Always kick - If there is a resource conflict, immediately kick the other resource. in Server>server settings>resource policy.
I'm having trouble getting started with GCDAsyncSocket to use a telnet connection.
When I connect through terminal I get some text and it asks me to login.
With GCDAsyncSocket I can get a connection but can't get any text from it.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%s",__FUNCTION__);
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err = nil;
if (![socket connectToHost:#"192.168.1.1" onPort:23 error:&err])
{
// If there was an error, it's likely something like "already connected" or "no delegate set"
NSLog(#"I goofed: %#", err);
}
[socket readDataWithTimeout:5 tag:1];
}
.
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
NSLog(#"Cool, I'm connected! That was easy.");
}
.
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(#"%s",__FUNCTION__);
NSString *responce = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"responce=%#",responce);
}
data responds with fffd01ff fd1ffffb 01fffb03
response is always null.