Gcdasyncsocket Multiple Connections Wont Accept Data from Multiple Sockets

GCDAsyncSocket doesn't send data to TCP Socket server

And I figured out with the solution.
Just add "\n" to the end of your message...

let jsonDataString = String(bytes: try! encoder.encode(imageModel), encoding: .utf8)! + "\n"
let jsonData = jsonDataString.data(using: .ascii)

GCDAsyncSocket: [socket acceptOnPort: error:] not accepting

I imagine your issue relates to your device not having a routable IP address from the outside world. I have assumed here that you are not testing on a local network with your server and phone both using this network via wifi/cable.

When you are on your device using a mobile network, it is assigned an IP address from the mobile operator. This address is more than likely an address which is part of their internal mobile network. When you connect outside of the mobile network to a server, the address the server sees for your device is not the address you see on the device. The addresses are mapped in transit as your IP packet passes through the various gateways while on its way to the server. Thus when you server sees a connection requested on a listen socket, it has a reply address which when used allows the reply to traverse back to your device.

A similar issue occurs when your device is on WiFi behind a NAT router. Connections made outgoing are seen by the router and it changes the from IP address to be that of the router. Since it sees the start of the conversation, it know where return packets with a given port and sequencing should be routed. However if somebody wants to connect to your device from outside, you have to have set up port forwarding on the router for a known port telling it where to send connection packets.

So applying this to your situation:

Outgoing Works (Why):

Your outgoing socket works, because you are connecting to an externally visible IP. When you connect, the network knows exactly where the packet has to go and the reply address is provided in the packet by the network.

Incoming Does Not Work (Why):

Your listen socket will not be working because the address you are sending to does not exist on the open internet. To make a connection from the server or anywhere else to your device you would need an IP which has a routing mapped through to your device. If the device is on a mobile network, you need an external IP for the mobile network which maps to your device. If the device was behind a NAT router, you would need port forwarding set up.

Solution:

Unfortunately, there is no easy solution as your need an IP address for your device in the outside world. Much depends on your use case which you have not mentioned. You either need an external IP which is reliable or you need to use an intermediate server to handle messaging or you need to change your approach and have the device poll every so often for information.

This is a problem which has existed for a long time and is why peer to peer companies have smart algoithms for connecting peer to peer services which use clever techniques like hole punching to connect devices.

IMHO I would move to a model where your device always initiates the connection if you can.

Does GCDAsyncSocket can readData automaticlly

You only need to call it once, but when socket:didReadData:withTag: is called, you will need to call readDataWithTimeout: again if you are expecting more data.

an example i have lying around(in swift):

func socket(sock: GCDAsyncSocket!, didAcceptNewSocket newSocket: GCDAsyncSocket?) {
println("new connection recieved \(newSocket?.hash) old: \(sock?.hash)");

socketRead = newSocket;

self.socketRead?.readDataToData(self.dataDelimiter, withTimeout: -1, tag: 0) //start reading
}

func socket(sock: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {

var mutableData:NSMutableData = NSMutableData();
mutableData.appendBytes(data.bytes, length: data.length-dataDelimiter.length) //remove delimiter
var error:NSError?
var jsonDic:NSDictionary? = NSJSONSerialization.JSONObjectWithData(mutableData, options: NSJSONReadingOptions.allZeros, error: &error) as? NSDictionary;

//println("did read data: \(NSString(data: mutableData, encoding: NSUTF8StringEncoding))")

if(sock == socketRead){

if(jsonDic != nil){
serverSentMessage(jsonDic!)
}

self.socketRead?.readDataToData(self.dataDelimiter, withTimeout: -1, tag: 0) //continue reading data
}
//have other sockets that only need to read once ever so dont do anything for those
}

Synchronous communication using GCDAsyncSocket

The easiest approach is to append your requests to a serial dispatch queue and then wait for them to be completed by using dispatch_sync(). A discussion on StackOverflow can be found here.

The actual way of implementing it is up to your preferences. A possible idea is the following:

  • Create a new class "SyncRequest"
  • This class ideally has a private property of type bool "requestFinished", initialized to NO in the class' init method
  • In a method such as "sendSyncRequest" you call submitMessage:completionBlock:
  • The completion block will set the "requestFinished" property to YES
  • The last line in "sendSyncRequest" will be dispatch_sync(syncRequestQueue, ^(void){while(!requestFinished);});

This way you can construct multiple instances of SyncRequest, each handling a synchronized request. Rough sketch implementation:

@interface SyncRequest
@property bool requestFinished;
@end

@implementation SyncRequest

dispatch_queue_t syncRequestQueue;

-(id)init
{
self = [super init];
if ( !self )
return nil;

self.requestFinished = NO;
syncRequestQueue = dispatch_queue_create("com.yourid.syncrequest", DISPATCH_QUEUE_SERIAL);

return self;
}

-(void) sendSyncRequest:(NSDictionary*)messageObject
{
// submit message here and set requestFinished = YES in completion block

// wait for completion here
dispatch_sync(syncRequestQueue, ^(void){while(!self.requestFinished);});
}

@end

NOTE: I wrote the code without having the compiler at hand, you may have to create an indirect reference to "self" in the dispatch_sync call in order to avoid a cyclic reference.

GCDAsyncSocket Client not reading until write

The answer is that one of the higher objects in my object chain was released early, causing the socket to be released early as well. Word to the wise it seems.



Related Topics



Leave a reply



Submit