Created
April 23, 2016 02:17
-
-
Save limboinf/c21fc65c31d2d5e42acef6f18910def7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.c | |
// C_lang | |
// | |
// Created by 方朋 on 16/4/21. | |
// Copyright © 2016年 方朋. All rights reserved. | |
// | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <time.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <string.h> | |
#define BUFFER_SIZE 1023 | |
int setnonblocking(int fd); | |
int unblock_connection(const char *, int, int); | |
int main(int argc, const char * argv[]) { | |
if (argc <= 2) { | |
fprintf(stderr, "Usage: %s ip_address port.\n", argv[0]); | |
return 1; | |
} | |
const char *ip = argv[1]; | |
int port = atoi(argv[2]); | |
int sockfd = unblock_connection(ip, port, 10); | |
if (sockfd < 0) return 1; | |
close(sockfd); | |
return 0; | |
} | |
/** | |
* | |
* @param: fd 文件描述符 | |
* return: flags 原先的文件描述符状态flags | |
**/ | |
int setnonblocking(int fd) | |
{ | |
int flags = fcntl(fd, F_GETFL, 0); | |
//设置为非阻塞 | |
if (fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0) { | |
perror("fcntl error"); | |
} | |
return flags; | |
} | |
int unblock_connection(const char *ip, int port, int time) | |
{ | |
int ret; | |
struct sockaddr_in sockaddr; | |
bzero(&sockaddr, sizeof(sockaddr)); | |
sockaddr.sin_family = AF_INET; | |
sockaddr.sin_port = htons(port); | |
inet_pton(AF_INET, ip, &sockaddr.sin_addr); | |
int sockfd = socket(PF_INET, SOCK_STREAM, 0); | |
// 设置非阻塞 | |
int fdopt = setnonblocking(sockfd); | |
ret = connect(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); | |
if (ret == 0) { | |
//如果连接成功则恢复sockfd的属性,并立即返回之 | |
printf("connect with server immediately\n"); | |
fcntl(sockfd, F_SETFL, fdopt); // 为什么要恢复sockfd的原来属性呢?? | |
return sockfd; | |
} else if (errno != EINPROGRESS) { | |
// 如果errno不是EINPROGRESS则表示出错,为EINPROGRESS表示连接还在进行 | |
fprintf(stderr, "unblock connect not support\n"); | |
return -1; | |
} | |
// 那么接下来的情况就是EINPROGRESS了 | |
fd_set reads; | |
fd_set writes; | |
FD_ZERO(&reads); //清空可读文件描述符的所有位 | |
FD_SET(sockfd, &writes); | |
struct timeval timeout; | |
timeout.tv_sec = time; | |
timeout.tv_usec = 0; | |
ret = select(sockfd+1, &reads, &writes, NULL, &timeout); | |
if (ret <= 0) { | |
// select 超时或出错 | |
fprintf(stderr, "select timeout or error\n"); | |
close(sockfd); | |
return -1; | |
} | |
if(!FD_ISSET(sockfd, &writes)) { | |
fprintf(stderr, "no event on select found\n"); | |
close(sockfd); | |
return -1; | |
} | |
int error = 0; | |
socklen_t length = sizeof(error); | |
//调用getsockopt来获取并清除sockfd上的错误 | |
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0) { | |
fprintf(stderr, "get socket option failed\n"); | |
close(sockfd); | |
return -1; | |
} | |
// 如果错误号非0表示连接出错 | |
if (error != 0) { | |
fprintf(stderr, "connection failed after select with error:%d\n", errno); | |
close(sockfd); | |
return -1; | |
} | |
//连接成功 | |
printf("connection ready after select with the socket:%d\n", sockfd); | |
fcntl(sockfd, F_SETFL, fdopt); | |
return sockfd; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment