When the function CFSocketConnectToAddress return kCFSocketError, how to get error reason, such as "not connected to Internet"?

When the function

CFSocketConnectToAddress
return
kCFSocketError
, I only know that the connection failed, I don't know why. I want to know why the connection fails.

I know if I pass a negative value to the

timeout
parameter, I can receive the
error code
in
kCFSocketConnectCallBack
when
CFSocketConnectToAddress
failed. But I must pass a positive value to the
timeout
parameter, because I want to limit connection time.

If you know how, tell me please. Thanks.

Replies

Why are you using

CFSocket
?
CFSocket
is effectively an implementation detail of higher-level APIs. Back in the day, there were some specific situations where
CFSocket
was the only way to achieve some certain goals (like integrating UDP with the runloop, or listening for incoming connections), but these days that’s no longer the case. I can’t think of any situation where
CFSocket
is the right answer any more, and you’ll have an easier time of things if you avoid it entirely.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank your answer.

I am trying to use CFStream to connect a server, as follows.

Now, I encountered two problems:

1. I do not know how to set timeout. When using CFSocket, I set timeout like this: CFSocketConnectToAddress(self.socket, sin_cfd, 3);

2. I do not know how to close the connection. I used the following method closeConnection to close the connection, although the connection is successfully closed but the subthread is not released.


Could you help me resovle the two problems ?

Thanks !


- (void)start
{
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(connectOnSubthread) object:nil];
    [thread start];
}

- (void)connectOnSubthread
{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)_domain, _port, &readStream, &writeStream);
    
    CFReadStreamSetProperty(readStream,  kCFStreamPropertyShouldCloseNativeSocket,  kCFBooleanTrue);
    CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
    
    _inputStream = (__bridge NSInputStream *)readStream;
    _outputStream = (__bridge NSOutputStream *)writeStream;
    
    _inputStream.delegate = self;
    _outputStream.delegate = self;

    [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [_inputStream open];
    [_outputStream open];
    
    [[NSRunLoop currentRunLoop] run];
}


- (void)closeConnection
{
    [_inputStream close];
    [_outputStream close];
    _inputStream = nil;
    _outputStream = nil;
}

First up, don’t use

CFSocket
for outgoing TCP connections. While
CFSocket
was useful in some corner cases back in the day, it’s never been the right option for outgoing TCP connections.

Next,

CFSocketStream
does not have a connection timeout function, but that’s not strictly speaking necessary. You can implement your own timeout using
NSTimer
. That is, schedule your streams to run asynchronously on the run loop, and schedule a timeout timer on that same run loop. If the connection succeeds before the timer fires, cancel the timer. If the timer fires before the connection succeeds, cancel the connection.

Finally, with regards the code you posted, you’re creating a separate thread to run your connection. This is generally not a good idea. Threads are relatively expensive, so it’s best to schedule all of your connections on the same thread. The easiest option is to use the main thread for this. This is convenient and safe as long as your stream event handler doesn’t block for too long.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"