Reputation: 617
I've inherited a iPhone application/project that opens a socket connection to another device (think web cam). This works fine as long as the device is reachable over the wifi network. However, if it isn't reachable, the application hangs calling "connect".
(Error checking stripped out for clarity.)
-(void)connect_to_control:(NSTimer*) timer
{
clientsock_fd = socket(AF_INET, SOCK_STREAM, 0);
int no_delay = 1;
setsockopt(clientsock_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, 4);
struct sockaddr_in the_addr;
memset((void *)&the_addr, 0, sizeof(the_addr));
the_addr.sin_family = AF_INET;
the_addr.sin_port = htons(25556);
const char* server_addr = "192.168.3.22";
unsigned long ip_addr = inet_addr(server_addr);
the_addr.sin_addr.s_addr = ip_addr;
int err_test = connect(clientsock_fd, (const struct sockaddr*)&the_addr, sizeof(the_addr));
}
My first thought was to "ping" the address to see if it is reachable. So far I've discovered Apples "Reachability" sample but that does NOT determine if an address is reachable, only if the network is reachable (except in the simulator) and an old Apple sample "SimplePing" which uses header files that aren't included in the iPhone SDK.
I've got decades of C++/C# experience but I'm an iPhone noob trying to help out a friend's little company debug some stuff in time for an important trade show. Thanks in advance.
Upvotes: 2
Views: 5550
Reputation: 617
For whatever reason, I was not able to get a non blocking solution using "select" working. (But thank you both for your helpful responses.) I ended up using one of the socket options that let me specify a shorter timeout.
setsockopt(clientsock_fd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &timeout, sizeof(timeout));
In the interest of completeness, this is what I ended up with (error checking removed for clarity):
-(void)connect_to_control:(NSTimer*) timer
{
clientsock_fd = socket(AF_INET, SOCK_STREAM, 0);
int no_delay = 1;
int result = setsockopt(clientsock_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, 4);
// *** Set timeout value to stop hanging ***
struct timeval timeout;
timeout.tv_sec =1;
timeout.tv_usec =0;
result = setsockopt(clientsock_fd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &timeout, sizeof(timeout));
struct sockaddr_in the_addr;
memset((void *)&the_addr, 0, sizeof(the_addr));
the_addr.sin_family = AF_INET;
the_addr.sin_port = htons(25556);
const char* server_addr = "192.168.3.22";
unsigned long ip_addr = inet_addr(server_addr);
the_addr.sin_addr.s_addr = ip_addr;
int err_test = connect(clientsock_fd, (const struct sockaddr*)&the_addr, sizeof(the_addr)); // hangs here when address can't be reached!
NOTE: I had to upgrade to OS 3.0 to use TCP_CONNECTIONTIMEOUT
. TCP_CONNECTIONTIMEOUT is defined in "tcp.h" the OS 3.0 SDK headers but not in OS 2.1. It is not defined in the simulator headers, only the device headers.
Upvotes: 0
Reputation: 20136
Firstly put the socket into non blocking mode, this means a connect will always return straight away:
lags = fcntl(sock,F_GETFL,0);
fcntl(sock,F_SETFL, flags | O_NONBLOCK)
Then you use the select statement with a timeout value to check if the connection has succeded yet:
select(FD_SETSIZE,0,&wset,0,&timeout)
You can find full explanation of non blocking sockets here
Upvotes: 1
Reputation: 48280
See this question to learn how to put a socket into non-blocking mode.
This is probably what you want to do, as a host may respond to pings even though it's not listening on a particular socket, and vice-versa.
Upvotes: 2