CocoaAsyncSocket's read and write delegates are not firing & code organization - objective-c

I'm trying to do the following with a modified version of the echo server example that comes with the cocoaasyncsocket library:
1) open a connection to a python script acting as a server
2) send data // works, but delegate doesn't fire
3) receive data back // delegate doesn't fire
4) disconnect // doesn't disconnect, apparently still in my thread
Currently I open a connection in the didFinishLaunchingWithOptions delegate, and then attempt to send data in the didConnectToHost delegate. I then attempt to read data coming back from the client and then disconnect.
I am able to open a connection and send data (which the server verifies as received) but the didWriteDataWithTag delegate never fires. However, the server receive the data. The server then fires back some data, but the didReadData doesn't fire either.
Beside the fact the read/write delegates aren't firing, it seems the way I'm organizing my code is not right, but I'm not sure how this looks in an event-driven system as opposed to run loop (I'm a novice at event-driven stuff + networking). If I have a series of actions whose respective completions are triggered by their delegates, should the delegates be sharing some sort of messages- ie we recieved an "xxx" message, write back "yyy"? I'd prefer to have one function which manages all of this. Is there a canonical way of doing this?
IPhoneConnectTestAppDelegate.m (snippets)
- (void)localConnect {
NSError *error = nil;
if (![asyncSocket connectToHost:#"localhost" onPort:5000 error:&error]) {
DDLogError(#"Error connecting: %#", error);
}
}
- (void)disconnect {
[asyncSocket setDelegate:nil];
[asyncSocket disconnect];
[asyncSocket release];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Setup our socket (GCDAsyncSocket).
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
[self localConnect];
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"didReadData: %#", output);
}
- (void)onSocket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(#"didWriteDataWithTag");
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
if(port == 5000)
{
NSString *msg = #"q";
NSData *dataOut = [msg dataUsingEncoding:NSASCIIStringEncoding];
[asyncSocket writeData:dataOut withTimeout:-1 tag:0];
[asyncSocket readDataWithTimeout:-1 tag:0];
[self disconnect];
}
}
tcpserver.py
# TCP server example
import socket, time
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 5000))
server_socket.listen(5)
print "TCPServer Waiting for client on port 5000"
while 1:
client_socket, address = server_socket.accept()
print "I got a connection from ", address
while 1:
data = client_socket.recv(512)
print "Data from client",data
time.sleep(2)
data = "xxx"
print "Sending data to client",data
client_socket.send (data)
break;

I know this is an old question with an already accepted answer, but to clarify for people who find this thread looking for something, the reason the delegate methods didn't get called is because the GCDAsynchSocket start with socket: instead of onsocket: ie:
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
becomes:
- (void) socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag

A friend of a friend figured it out for me! We were not able to get GCDAsyncSocket to work properly (connect and write, but not read). AsyncSocket however functions in all 3 respects, and all the delegates work properly.
#import "AsyncSocket.h"
#import "tcp_clientViewController.h"
#implementation tcp_clientViewController
#synthesize socket;
-(IBAction)connect:(id)sender {
NSLog(#"(IBAction)connect");
NSError *error = nil;
if (![socket connectToHost:#"localhost" onPort:5000 error:&error]){
NSLog(#"Error connecting: %#", error);
}
}
-(IBAction)send:(id)sender {
NSLog(#"(IBAction)send");
char bytes[] = "abcd\r\n";
NSData* data = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];
//NSString *msg = #"xxxxx\r\n";
//NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[socket writeData:data withTimeout:-1 tag:0];
//NSData *data = [asyncSocket readDataWithTimeout:-1 tag:0];
[data release];
[socket readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];
}
- (void)viewDidLoad {
// initialize socket
socket = [[AsyncSocket alloc] initWithDelegate:self];
}
#pragma mark AsyncSocket Delegate Methods
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(#"socket:%p didWriteDataWithTag:%#", sock, tag);
}
- (void)socket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
NSLog(#"socket:%p didWritePartialDataOfLength:%# tag:%#", sock, partialLength, tag);
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
}
- (void)socketDidSecure:(AsyncSocket *)sock
{
NSLog(#"socket:%p socketDidSecure", sock);
}
- (void)socketDidDisconnect:(AsyncSocket *)sock withError:(NSError *)err
{
NSLog(#"socket:%p socketDidDisconnect withError: %#", sock, err);
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString* newStr = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"socket socketDidReadData:%#", newStr);
}
-(IBAction)disconnect:(id)sender { }
#pragma mark View stuff
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {}
- (void)dealloc {
self.socket = nil;
[super dealloc];
}
#end

Try to use local sock for reading commands and to put them in the write command
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:tag];
}

Related

Error while binding a socket : NSPOSIXErrorDomain Code=1 "Operation not permitted"

I'm trying to implement GCDAsyncSocket to mac os x (Mojave 10.14.3) application to listen data from localhost:port.
The problem is no matter what port I choose I always get this error:
Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"
UserInfo={NSLocalizedDescription=Operation not permitted,
NSLocalizedFailureReason=Error in bind() function}
I've already tried this, but it didn't work.
Here is my implementation in AppDelegate.mm:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:(id<GCDAsyncSocketDelegate>) self delegateQueue:dispatch_get_main_queue()];
connectedSockets = [[NSMutableArray alloc] initWithCapacity:1];
isRunning = NO;
NSError *err = nil;
if (![listenSocket connectToHost:#"localhost" onPort:12345 error:&err]){
NSLog(#"I goofed: %#", err);
}
}
-(void)getData{
if(!isRunning)
{
int port = 12345;
if(port < 0 || port > 65535)
{
port = 0;
}
NSError *error = nil;
if(![listenSocket acceptOnPort:port error:&error])
{
NSLog(#"error: %#", FORMAT(#"Error starting server: %#", error));
return;
}
NSLog(#"error: %#", FORMAT(#"Echo server started on port %hu", [listenSocket localPort]));
isRunning = YES;
}
else
{
// Stop accepting connections
[listenSocket disconnect];
// Stop any client connections
NSUInteger i;
for(i = 0; i < [connectedSockets count]; i++)
{
[[connectedSockets objectAtIndex:i] disconnect];
}
NSLog(#"Stopped Echo server");
isRunning = false;
}
}
- (void)onSocket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
[connectedSockets addObject:newSocket];
}
- (void)onSocket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(FORMAT(#"Accepted client %#:%hu", host, port));
NSString *welcomeMsg = #"Welcome to the AsyncSocket Echo Server\r\n";
NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:welcomeData withTimeout:-1 tag:WELCOME_MSG];
[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0];
}
- (void)onSocket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
if(tag == ECHO_MSG)
{
[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0];
}
}
- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length] - 2)];
NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
if(msg)
{
NSLog(#"msg %#", msg);
}
else
{
NSLog(#"Error converting received data into UTF-8 String");
}
// Even if we were unable to write the incoming data to the log,
// we're still going to echo it back to the client.
[sock writeData:data withTimeout:-1 tag:ECHO_MSG];
}
- (NSTimeInterval)onSocket:(GCDAsyncSocket *)sock
shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length
{
if(elapsed <= READ_TIMEOUT)
{
NSString *warningMsg = #"Are you still there?\r\n";
NSData *warningData = [warningMsg dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:warningData withTimeout:-1 tag:WARNING_MSG];
return READ_TIMEOUT_EXTENSION;
}
return 0.0;
}
- (void)onSocket:(GCDAsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(FORMAT(#"Client Disconnected: %#:%hu", [sock connectedHost], [sock connectedPort]));
}
- (void)onSocketDidDisconnect:(GCDAsyncSocket *)sock
{
[connectedSockets removeObject:sock];
}
I'm not sure about if my implementation is wrong or I should get any kind of permissions granted.
Any help would be appreciated!
You should enable its network capability of the App Sandbox
macOS Catalina Version 10.15.3:

Objective-c threading and cpu performance

I have an app which downloads some files from the server in few threads. The problems is that it is giving a heavy load to the CPU (hitting to 80%). What can be done to make it better? I made similar app on Windows with C#, and the cpu usage never goes above 5%.
EDIT: This code has been changed after getting some suggestions below. The problem now is, that the download never reaches 100% when I set [queue setMaxConcurrentOperationCount:6]. If I change the asynchronous NSURLConnection back to sendSynchronous call it works, when I change the above OperationCount to 1, also works.
This is how I add NSOperations to the queue (may be large, like 800).
int chunkId = 0;
for (DownloadFile *downloadFile in [download filesInTheDownload])
{
chunkId = 0;
for (DownloadChunk *downloadChunk in [downloadFile chunksInTheFile])
{
DownloadChunkOperation *operation = [[DownloadChunkOperation alloc] initWithDownloadObject:download
downloadFile:downloadFile downloadChunk:downloadChunk andChunkId:chunkId];
[queue addOperation:operation];
chunkId++;
}
}
#import "DownloadChunkOperation.h"
#import "Download.h"
#import "DownloadFile.h"
#import "DownloadChunk.h"
#interface DownloadChunkOperation()
#property(assign) BOOL isExecuting;
#property(assign) BOOL isFinished;
#end
#implementation DownloadChunkOperation
#synthesize download = _download;
#synthesize downloadFile = _downloadFile;
#synthesize downloadChunk = _downloadChunk;
#synthesize isFinished = _isFinished;
#synthesize isExecuting = _isExecuting;
- (id) initWithDownloadObject:(Download *)download downloadFile:(DownloadFile *)downloadFile downloadChunk:(DownloadChunk *)downloadChunk andChunkId:(uint32_t)chunkId
{
self = [super init];
if (self) {
self.download = download;
self.downloadFile = downloadFile;
self.downloadChunk = downloadChunk;
self.chunkId = chunkId;
}
return self;
}
- (void) start
{
if ([self isCancelled]) {
[self setIsFinished:YES];
[self setIsExecuting:NO];
return;
}
[self setIsExecuting:YES];
[self setIsFinished:NO];
[self.downloadChunk setChunkState:cDownloading];
downloadPath = [[NSString stringWithFormat:#"%#/%#", [self.download downloadFolder], [self.download escapedTitle]] stringByExpandingTildeInPath];
NSURL *fileURL = [[NSURL alloc] initWithString:[self.downloadFile filePath]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL];
NSString *range = [NSString stringWithFormat:#"bytes=%lli-%lli", [self.downloadChunk startingByte], [self.downloadChunk endingByte]];
[request setValue:range forHTTPHeaderField:#"Range"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// IMPORTANT! The next line is what keeps the NSOperation alive for the during of the NSURLConnection!
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
if (connection) {
NSLog(#"connection established!");
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!self.isFinished);
} else {
NSLog(#"couldn't establish connection for: %#", fileURL);
}
}
- (BOOL) isConcurrent
{
return YES;
}
- (void) connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response
{
receivedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Not cancelled, receive data.
if (![self isCancelled]) {
[receivedData appendData:data];
self.download.downloadedBytes += [data length];
return;
}
// Cancelled, tear down connection.
[self setIsExecuting:NO];
[self setIsFinished:YES];
[self.downloadChunk setChunkState:cConnecting];
[self->connection cancel];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self setIsExecuting:NO];
[self setIsFinished:YES];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *chunkPath = [downloadPath stringByAppendingFormat:#"/%#.%i", [self.downloadFile fileName], self.chunkId];
NSError *saveError = nil;
[receivedData writeToFile:chunkPath options:NSDataWritingAtomic error:&saveError];
if (saveError != nil) {
NSLog(#"Download save failed! Error: %#", [saveError description]);
}
else {
NSLog(#"file has been saved!: %#", chunkPath);
}
[self setIsExecuting:NO];
[self setIsFinished:YES];
[self.downloadChunk setChunkState:cFinished];
if ([self.download downloadedBytes] == [self.download size])
[[NSNotificationCenter defaultCenter] postNotificationName:#"downloadFinished" object:self.download];
}
#end
You should not create threads yourself. Use dedicated API like NSOperationQueue or even GCD directly for this purpose. They know better about hardware limits, virtual cores, etc. and support priority settings.
You shouldn't use +sendSynchronousRequest: either. Wrapping your -downloadChunk method in a dispatch call as suggested by charith won't help you improve performance, as +sendSynchronousRequest: blocks the thread until new data comes in and forces GCD to spawn new threads.
Use the asynchronous API of NSURLConnection using delegate callbacks. You can also wrap your NSURLConnection code inside a NSOperation subclass and use NSOperationQueue to manage the downloads: Using NSURLConnections
If you don't want to write the NSOperation subclass yourself, you can also use a 3rd party framework like AFNetworking.
Try with GCD blocks and global queues. This is the apple recommended way now for concurrency ex:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
[self downloadChunk:objDownload];
});

AFNetworking Synchronous Operation in NSOperationQueue on iPhone

My app is working this way :
- create an album and take pictures
- send them on my server
- get an answer / complementary information after picture analysis.
I have some issue with the sending part. Here is the code
#interface SyncAgent : NSObject <SyncTaskDelegate>
#property NSOperationQueue* _queue;
-(void)launchTasks;
#end
#implementation SyncAgent
#synthesize _queue;
- (id)init
{
self = [super init];
if (self) {
self._queue = [[NSOperationQueue alloc] init];
[self._queue setMaxConcurrentOperationCount:1];
}
return self;
}
-(void) launchTasks {
NSMutableArray *tasks = [DataBase getPendingTasks];
for(Task *t in tasks) {
[self._queue addOperation:[[SyncTask alloc] initWithTask:t]];
}
}
#end
and the SyncTask :
#interface SyncTask : NSOperation
#property (strong, atomic) Task *_task;
-(id)initWithTask:(Task *)task;
-(void)mainNewID;
-(void)mainUploadNextPhoto:(NSNumber*)photoSetID;
#end
#implementation SyncTask
#synthesize _task;
-(id)initWithTask:(Task *)task {
if(self = [super init]) {
self._task = task;
}
return self;
}
-(void)main {
NSLog(#"Starting task : %#", [self._task description]);
// checking if everything is ready, sending delegates a message etc
[self mainNewID];
}
-(void)mainNewID {
__block SyncTask *safeSelf = self;
[[WebAPI sharedClient] createNewPhotoSet withErrorBlock:^{
NSLog(#"PhotoSet creation : error")
} andSuccessBlock:^(NSNumber *photoSetID) {
NSLog(#"Photoset creation : id is %d", [photoSetID intValue]);
[safeSelf mainUploadNextPhoto:photoSetID];
}];
}
-(void)mainUploadNextPhoto:(NSNumber*) photoSetID {
//just admit we have it. won't explain here how it's done
NSString *photoPath;
__block SyncTask *safeSelf = self;
[[WebAPI sharedClient] uploadToPhotosetID:photoSetID withPhotoPath:photoPath andErrorBlock:^(NSString *photoPath) {
NSLog(#"Photo upload error : %#", photoPath);
} andSuccessBlock:^(NSString *photoPath) {
NSLog(#"Photo upload ok : %#", photoPath);
//then we delete the file
[safeSelf mainUploadNextPhoto:photoSetID];
}];
}
#end
Every network operations are done using AFNetworking this way :
-(void)myDummyDownload:(void (^)(NSData * data))successBlock
{
AFHTTPClient* _httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.google.com/"]];
[_httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path:#"/" nil];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:(NSURLRequest *)request
success:^(AFHTTPRequestOperation *operation, id data) {
if(dataBlock)
dataBlock(data);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Cannot download : %#", error);
}];
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{
NSLog(#"Request time out");
}];
[_httpClient enqueueHTTPRequestOperation:operation];
}
My problem is : my connections are made asynchronously, so every task are launched together without waiting fo the previous to finish even with [self._queue setMaxConcurrentOperationCount:1] in SyncAgent.
Do I need to perform every connection synchronously ? I don't think this is a good idea, because a connection never should be done this way and also because I might use these methods elsewhere and need them to be performed in background, but I cannot find a better way. Any idea ?
Oh and if there is any error/typo in my code, I can assure you it appeared when I tried to summarize it before pasting it, it is working without any problem as of now.
Thanks !
PS: Sorry for the long pastes I couldn't figure out a better way to explain the problem.
EDIT: I found that using a semaphore is easier to set up and to understand : How do I wait for an asynchronously dispatched block to finish?
If you have any control over the server at all, you should really consider creating an API that allows you to upload photos in an arbitrary order, so as to support multiple simultaneous uploads (which can be quite a bit faster for large batches).
But if you must do things synchronized, the easiest way is probably to enqueue new requests in the completion block of the requests. i.e.
// If [operations length] == 1, just enqueue it and skip all of this
NSEnumerator *enumerator = [operations reverseObjectEnumerator];
AFHTTPRequestOperation *currentOperation = nil;
AFHTTPRequestOperation *nextOperation = [enumerator nextObject];
while (nextOperation != nil && (currentOperation = [enumerator nextObject])) {
currentOperation.completionBlock = ^{
[client enqueueHTTPRequestOperation:nextOperation];
}
nextOperation = currentOperation;
}
[client enqueueHTTPRequestOperation:currentOperation];
The following code works for me, but I am not sure of the drawbacks. Take it with a pinch of salt.
- (void) main {
NSCondition* condition = [[NSCondition alloc] init];
__block bool hasData = false;
[condition lock];
[[WebAPI sharedClient] postPath:#"url"
parameters:queryParams
success:^(AFHTTPRequestOperation *operation, id JSON) {
//success code
[condition lock];
hasData = true;
[condition signal];
[condition unlock];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure code
[condition lock];
hasData = true;
[condition signal];
[condition unlock];
}];
while (!hasData) {
[condition wait];
}
[condition unlock];
}

GCDAsyncUdpSocket Multicast Gets HTTP 412 Response

I am building a iOS application that sends out a multicast message (SSDP) and listens for responses from devices that implement that protocol. I am using GCDAsyncUdpSocket to create the UDP socket to broadcast the SSDP message and receive responses. The problem that I am having is that the message the application receives from the all of the devices on the network is the same: a HTTP 412 response.
Here is my code:
Initialize socket
#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:0 error:&error])
{
NSLog(#"Error binding: %#", [error description]);
return;
}
if (![udpSocket beginReceiving:&error])
{
NSLog(#"Error receiving: %#", [error description]);
return;
}
[udpSocket enableBroadcast:YES error:&error];
if (error != nil)
{
NSLog(#"Error enableing broadcast: %#", [error description]);
return;
}
NSLog(#"Socket Created");
}
Create Socket
- (IBAction)socketFind:(id)sender
{
NSString *str = [[NSString alloc] initWithString:#"M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp discover\"\r\nMX: 3\r\nST: ssdp:all\r\nUSER-AGENT: iOS UPnP/1.1 TestApp/1.0\r\n\r\n"];
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
[udpSocket sendData:data toHost:#"239.255.255.250" port:1900 withTimeout:-1 tag:0];
NSLog(#"Sent Data");
}
Data Received Callback
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
NSLog(#"Did Receive Data");
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (msg)
{
NSLog(#"Message: %#",msg);
}
else
{
NSString *host = nil;
uint16_t port = 0;
[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
NSLog(#"Unknown Message: %#:%hu", host, port);
}
}
When the didReceiveData function is called, I get the following message:
Message: HTTP/1.1 412 Precondition Failed
Connection:close
CONTENT-LENGTH:0
This issue was with the M-Search string. I was missing the colon between sspd and discover. If you are getting a 412 response, I would make sure that you are formatting everything correctly. Turns out, that was my issue...

AsyncSocket WHOIS connect

I'm trying to connect to WHOIS servers (com.whois-servers.net:43) using GCDAsyncSocket. I can connect and write to the server and the didWriteDataWithTag: gets called but there is no data. The WHOIS server does in fact sends a response but I cant read it.
NSLog(#"Connecting to \"%#\" on port %hu...", host, port);
self.viewController.label.text = #"Connecting...";
NSError *error = nil;
if (![asyncSocket connectToHost:#"com.whois-servers.net" onPort:43 error:&error])
{
DDLogError(#"Error connecting: %#", error);
self.viewController.label.text = #"Oops";
}
NSString *requestStr = [NSString stringWithFormat:#"domain google.com\r\n\r\n"];
NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:requestData withTimeout:-1 tag:0];
[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
Here is the didReadData:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
DDLogInfo(#"socket:%p didReadData:withTag:%d", sock, tag);
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data: %i", [data length]);
}
Help?!
I ran into the same problem using AsyncSocket. I never fully solved it, but found a close solution.
In onSocket:willDisconnectWithError (GapSocketCommand.m) you can get the current buffer when the connection fails by calling unreadData.
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(#"onSocket:willDisconnectWithError %#",err);
NSData * unreadData = [sock unreadData]; // ** This gets the current buffer
if(unreadData) {
[self onSocket:sock didReadData:unreadData withTag:NULL]; // ** Return as much data that could be collected
} else {
NSString* jsString = [[NSString alloc] initWithFormat:#"GapSocket.__onError(\"%d\",\"%#\");"
,[sock userData]
,[err localizedDescription] ];
[self.webView stringByEvaluatingJavaScriptFromString:jsString];
//[jsString release];
}
}
You'll have to modify it to apply to GCDAsyncSocket, but the solution should be the same.