大家好,又见面了,我是你们的朋友全栈君。
man手册
EINPROGRESS The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for com‐pletion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <libgen.h> //for basename
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <sys/select.h>
#include <arpa/inet.h>
int setnonblocking(int fd);
int set_nonblocking_connect(const char* ip,const char* port,int time);
int main(int argc,char *argv[])
{
//must write ip and port
if(argc<3){
printf("usage:./%s [ip] [port]\n",basename(argv[0]));
exit(EXIT_FAILURE);
}
int cli_fd;
if((cli_fd=set_nonblocking_connect(argv[1],argv[2],10))==-1)
exit(EXIT_FAILURE);
sleep(10);
close(cli_fd);
exit(EXIT_SUCCESS);
}
/*****************************************************************************
函 数 名 : setnonblocking
功能描述 : 将参数所指的fd设置为非阻塞
输入参数 : int fd
输出参数 : 无
返 回 值 : int
失败退出程序,成功返回fd的旧标志
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2019年12月23日
作 者 : 江南_董少
修改内容 : 新生成函数
*****************************************************************************/
int setnonblocking(int fd)
{
int old_options=fcntl(fd,F_GETFL);
int new_options=old_options|O_NONBLOCK;
if(fcntl(fd,F_SETFL,new_options)==-1){
perror("fcntl");
exit(EXIT_FAILURE);
}
return old_options;
}
/*****************************************************************************
函 数 名 : set_nonblocking_connect
功能描述 :
输入参数 : const char* ip
int port
int time
输出参数 : 无
返 回 值 : int
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2019年12月23日
作 者 : 江南_董少
修改内容 : 新生成函数
*****************************************************************************/
int set_nonblocking_connect(const char* ip,const char* port,int time)
{
int sock_fd,old_options,ret_val;
struct sockaddr_in serAddress;
//socket
if((sock_fd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("socket");
exit(EXIT_FAILURE);
}
//set nonblock
old_options=setnonblocking(sock_fd);
//init address
bzero(&serAddress,sizeof(serAddress));
serAddress.sin_family=AF_INET;
serAddress.sin_port=htons(atoi(port));
if(inet_pton(AF_INET,ip,&serAddress.sin_addr.s_addr)==-1){
perror("inet_pton");
exit(EXIT_FAILURE);
}
//connect
//nonblocking connect success,return sock_fd
if((ret_val=connect(sock_fd,(struct sockaddr*)&serAddress,sizeof(serAddress)))==0){
printf("connect with server suucess\n");
//set fd block and return
if(fcntl(sock_fd,F_SETFL,old_options)==-1){
perror("fcntl");
exit(EXIT_FAILURE);
}
return sock_fd;
}
//nonblocking connect error
else if(errno!=EINPROGRESS){
printf("unblock connect not support\n");
return -1;
}
fd_set readfds;
fd_set writefds;
struct timeval timeout;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
timeout.tv_sec=time;
timeout.tv_usec=0;
ret_val=select(sock_fd+1,NULL,&writefds,NULL,&timeout);
if(ret_val<=0){
//select error or timeout,return
printf("connection time out\n");
close(sock_fd);
return -1;
}
//nonblocking connect fd is not ready write,return
if(!FD_ISSET(sock_fd,&writefds)){
printf("no events on sock_fd found\n");
close(sock_fd);
return -1;
}
int error=0;
socklen_t length=sizeof(error);
//get error and save to error
if(getsockopt(sock_fd,SOL_SOCKET,SO_ERROR,&error,&length)==-1){
perror("getsockopt");
exit(EXIT_FAILURE);
}
//error is not 0,meaning connect error
if(error!=0){
printf("connect failed after select with the error:%d\n",error);
close(sock_fd);
return -1;
}
//connect success
printf("connect ready after select with the socket:%d\n",sock_fd);
//set fd block and return
fcntl(sock_fd,F_SETFL,old_options);
return sock_fd;
}
测试①
测试②
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/160529.html原文链接:https://javaforall.cn