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.
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.
I try to connect telnet to my telnet server port 23 in iOS.
I use the "cocoaAsyncSocket" library.
I can received the data from the telnet.
But I try to decode to the string , the data is not my expect.
It will show
(null)
If I use NSASCIIStringEncodeing to decode.
It will show
ÿýÿý ÿý#ÿý'
I use the terminal command, telnet myIP 23.
I can get below in terminal.
james$ telnet 192.168.2.94 23
Trying 192.168.2.94...
Conn ected to txxxxx.xxxxx.com.
Escape character is '^]'.
Password:
how can I parse to the "Password:" string in iOS?
thank you .
my connect code below:
- (void)viewDidLoad {
[super viewDidLoad];
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
buffer = [[NSMutableData alloc] init];
[asyncSocket connectToHost:#"192.168.2.94" onPort:23 error:nil];
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(#"did connect to host");
[asyncSocket readDataWithTimeout:-1 tag:0];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(#"didReadData(%lu): %#", tag, #([data length]));
[buffer setLength:0];
NSString* message = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
// NSString* message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"message is: \n%#",message);
[asyncSocket readDataWithTimeout:-1 buffer:buffer bufferOffset:[buffer length] tag:tag];
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
NSLog(#"socket disconnect to host");
}
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.
I'm looking for sending serial commands to an OBD-II wi-fi device via my iPad.
In order to do it, I've use CocoaAsyncSocket lib to connect my iPad to the OBD-II and it works fine. Then, I've send a command "010C/r" to the device to get the rpm of the car, but it doesn't work. I think I don't use the right syntax to do it, but I'm not sure.
Here is my Objective-C code:
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#define HOST #"192.168.0.10"
#define USE_SECURE_CONNECTION 0
#define VALIDATE_SSL_CERTIFICATE 1
#define READ_HEADER_LINE_BY_LINE 0
#implementation SimpleHTTPClientAppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[DDLog addLogger:[DDTTYLogger sharedInstance]];
DDDispatchQueueLogFormatter *formatter = [[DDDispatchQueueLogFormatter alloc] init];
[formatter setReplacementString:#"socket" forQueueLabel:GCDAsyncSocketQueueName];
[formatter setReplacementString:#"socket-cf" forQueueLabel:GCDAsyncSocketThreadName];
[[DDTTYLogger sharedInstance] setLogFormatter:formatter];
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
NSString *host = HOST;
#if USE_SECURE_CONNECTION
uint16_t port = 443; // HTTPS
#else
uint16_t port = 35000; // HTTP
#endif
if (![asyncSocket connectToHost:host onPort:port error:&error])
{
DDLogError(#"Unable to connect to due to invalid configuration: %#", error);
}
else
{
DDLogVerbose(#"Connecting to \"%#\" on port %hu...", host, port);
}
#if USE_SECURE_CONNECTION
#if VALIDATE_SSL_CERTIFICATE
{
DDLogVerbose(#"Requesting StartTLS with options: (nil)");
[asyncSocket startTLS:nil];
}
#else
{
NSDictionary *options =
[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
DDLogVerbose(#"Requesting StartTLS with options:\n%#", options);
[asyncSocket startTLS:options];
}
#endif
#endif
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
DDLogVerbose(#"socket:didConnectToHost:%# port:%hu", host, port);
NSString *requestStrFrmt = #"010C\r";
NSString *requestStr = [NSString stringWithFormat:requestStrFrmt, HOST];
NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:requestData withTimeout:-1.0 tag:0];
DDLogVerbose(#"Sending HTTP Request:\n%#", requestStr);
#if READ_HEADER_LINE_BY_LINE
[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1.0 tag:0];
#else
NSData *responseTerminatorData = [#"\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding];
[asyncSocket readDataToData:responseTerminatorData withTimeout:-1.0 tag:0];
#endif
}
- (void)socketDidSecure:(GCDAsyncSocket *)sock
{
DDLogVerbose(#"socketDidSecure:");
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
DDLogVerbose(#"socket:didWriteDataWithTag:");
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
DDLogVerbose(#"socket:didReadData:withTag:");
NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
#if READ_HEADER_LINE_BY_LINE
DDLogInfo(#"Line httpResponse: %#", httpResponse);
if ([data length] == 2)
{
DDLogInfo(#"<done>");
}
else
{
[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1.0 tag:0];
}
#else
DDLogInfo(#"Full HTTP Response:\n%#", httpResponse);
#endif
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
DDLogVerbose(#"socketDidDisconnect:withError: \"%#\"", err);
}
#end
Here is the logs:
2014-05-28 17:02:05:559 [main] Connecting to "192.168.0.10" on port 35000...
2014-05-28 17:02:05:619 [main] socket:didConnectToHost:192.168.0.10 port:35000
2014-05-28 17:02:05:621 [main] Sending HTTP Request:
010C
2014-05-28 17:02:05:622 [main] socket:didWriteDataWithTag:
Thx
Try '010C\r' instead of '010C/r'. You are using the carriage return correctly, but the slash should be the other way!
OBD-II protocol uses the CR as a ending commando, if you don't send it, it will keep listening, but it should give a timeout when you wait for a long time, I believe. Need to check on that.
As per V.250, AT commands are terminated with \r\n.
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.