#include <assert.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
int main(){
int nfd = socket(AF_INET, SOCK_STREAM, 0 );
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(80); ///服务器端口
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip
int flags = fcntl(nfd, F_GETFL);
flags |= O_NONBLOCK;
int ret = fcntl(nfd, F_SETFL, flags);//注意放到connect前执行
if(ret == -1){
printf("set O_NONBLOCK failed!,errno=%d\n",errno);
}
ret = connect(nfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
if(-1 == ret){ //-1时有可能是还没连接上,通过EINPROGRESS判断
if(errno != EINPROGRESS){
printf("connect failed! %s %d\n", strerror(errno), errno);
return -1;
}
else
printf("connecting...\n");
}
else{ //这种情况是瞬间链接上的情况
printf("connect ok.\n");
return 0;
}
struct timeval tv;
fd_set readFds;
fd_set writeFds;
FD_ZERO(&readFds);
FD_ZERO(&writeFds);
FD_SET(nfd, &writeFds);
FD_SET(nfd, &readFds);
/*设置超时时间*/
tv.tv_sec = 10;
tv.tv_usec = 0;
ret = select(nfd+1, &readFds, &writeFds, NULL, &tv);
if(ret <= 0)
{
perror("select timeout or error");
close(nfd);
return -1;
}
//返回 可写 可读&可写
if(FD_ISSET(nfd, &writeFds))
{
//可读可写有两种可能,一是连接错误,二是在连接后服务端已有数据传来
if(FD_ISSET(nfd, &readFds))
{
if(connect(nfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
{
int error=0;
socklen_t length = sizeof(errno);
//调用getsockopt来获取并清除sockfd上的错误.
if(getsockopt(nfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
{
printf("get socket option failed\n");
close(nfd);
return -1;
}
if(error != EISCONN)
{
perror("connect error != EISCONN");
close(nfd);
return -1;
}
}
}
printf("connect ok.\n");
return 0;
}
else
{
perror("connect failed");
close(nfd);
return -1;
}
return 0;
}