三次握手同时做其他的处理。connect要花一个往返时间完成,从几毫秒的局域网到几百毫秒或几秒的广域网。这段时间可能有一些其他的处理要执行,比如数据准备,预处理等。
建立connect连接,此时socket设置为非阻塞,connect调用后,无论连接是否建立立即返回-1,同时将errno(包含errno.h就可以直接使用)设置为EINPROGRESS, 表示此时tcp三次握手仍旧进行,如果errno不是EINPROGRESS,则说明连接错误,程序结束。
当客户端和服务器端在同一台主机上的时候,connect回马上结束,并返回0,有时候也会返回-1; 当客户端与服务器不在同一主机上,一般情况都会返回-1;
所以需要使用select机制来检测connect是否已经连接上服务器;
注:需要设置为非阻塞模式
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0)
{
exit(1);
}
opts = opts|O_NONBLOCK;
if (fcntl(sock, F_SETFL, opts) < 0)
{
exit(1);
}
}
int connect2server(char *server,int port)
{
struct sockaddr_in dest;
fd_set fdr, fdw;
struct timeval timeout;
int res;
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(port);
if (inet_aton(server, (struct in_addr *) &dest.sin_addr.s_addr) == 0)
{
printf ("addr Socket disconnect !!!!!\n");
}
if(connect(g_sockfd, (struct sockaddr *)&dest, sizeof(dest)) != 0) {
if(errno != EINPROGRESS) { // EINPROGRESS
perror("Network test...\n");
close(g_sockfd);
return -1;
}
}
else {
printf("Connected\n");
return 0;
}
FD_ZERO(&fdr);
FD_ZERO(&fdw);
FD_SET(g_sockfd, &fdr);
FD_SET(g_sockfd, &fdw);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
res = select(g_sockfd + 1, &fdr, &fdw, NULL, &timeout);
if(res < 0) {
perror("Network test...\n");
close(g_sockfd);
return -1;
}
if(res == 0) {
printf("Connect server timeout");
close(g_sockfd);
return -1;
}
if(res == 1) {
if(FD_ISSET(g_sockfd, &fdw))
{
printf("Connected ok\n");
close(g_sockfd);
return 0;
}
}
/* Not necessary */
if(res == 2) {
printf("Connect server timeout");
close(g_sockfd);
return -1;
}
return -1;
}