I'm trying to test a server connection with the GCDAsyncSocket.
https://github.com/robbiehanson/CocoaAsyncSocket
I want to connect to a ip + port and get a message, whether it worked, or not.
I'm so far right now.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
NSString *host = #"www.google.de";
uint16_t port = 21;
NSError *error = nil;
if(![asyncSocket connectToHost:host onPort:port error:&error])
{
NSLog(#"ERROR %#!!!", error);
}
else{
NSLog(#"NO ERROR %#!!!", error);
}
[asyncSocket writeData:#"DATA" withTimeout:3 tag:0];
return YES;
}
But how can i check whether the Data was written or not?
if(![asyncSocket connectToHost:host onPort:port error:&error])
always get me a no error.
You have to implement the socket:didWriteDataWithTag: delegate method.
From "GCDAsyncSocket.h":
/**
* Called when a socket has completed writing the requested data. Not called if there is an error.
**/
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
If the write times out then the connection is closed and the delegate method
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
is called.
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 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.
Im am trying to properly integrate MBProgressHUD in a project while i am downloading and processing some data. Forgive me my ignorance if i am asking stupid things, but i'm a complete noob...
I have a "Data" class that is handling my HTTPRequests, so i thing here is the proper place to put some stuff in:
-(void)resolve
{
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[[NSURL alloc] initWithString:[self url]]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"Resolving content from: %#",[self url]);
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
NSLog(#"Content - resolve: connection failed");
}
// Here is the part that it makes me crazy...
HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain];
return;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
expectedLength = [response expectedContentLength];
currentLength = 0;
HUD.mode = MBProgressHUDModeDeterminate;
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
return;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[HUD hide:YES];
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Content - Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
return;
}
Now i know that putting the "showHUDaddedTo" in the -(void)resolve is not the right way...
I am calling this data function from a view controller with an IBaction like this:
-(IBAction) btnClicked:(id) sender {
if ([[issue status] intValue] == 1 ) // issue is not downloaded
{
[(Content *)[issue content] resolve];
//HUD = [[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES] retain];
}
else // issue is downloaded - needs to be archived
{
NSError * error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[(Content *)[issue content] path] error:&error];
if (error) {
// implement error handling
}
else {
Content * c = (Content *)[issue content];
[c setPath:#""];
[issue setStatus:[NSNumber numberWithInt:1]];
[buttonView setTitle:#"Download" forState:UIControlStateNormal];
[gotoIssue setTitle:#"..." forState:UIControlStateNormal];
// notify all interested parties of the archived content
[[NSNotificationCenter defaultCenter] postNotificationName:#"contentArchived" object:self]; // make sure its persisted!
}
}
}
Simply said: i would like to call all the MBProgressHUD stuff from my Conten.m file in the moment i push the download button in my IssueController.m file. I think you see now where my problem is: i am not a coder ;-) Any help is appreciated.
Cheers,
sandor
I would try and use the HUD method showWhileExecuting. Wrap your calls up in a new method and call that to download your information. When your method finishes, so will your HUD.
Also, is there a reason why you are retaining your calls for the HUD? I have not seen that before and I'm not sure if you need to retain those as they are autoreleased.