使用 select 设计超时 connect 函数的问题(linux 上连接 127.0.0.1 任何端口总是成功)

http://www.programfan.com/club/showpost.asp?id=24642

【hzhxxx】:
今天仔细 看了 man connect,明白了错误的原因:
EINPROGRESS
              The  socket  is  non-blocking and the connection
              cannot be completed immediately.  It is possible
              to   select(2)  or  poll(2)  for  completion  by
              selecting  the   socket   for   writing.   After
              select(2)  indicates  writability,  use getsock-
              opt(2) to read  the  SO_ERROR  option  at  level
              SOL_SOCKET  to  determine whether connect() com-
              pleted successfully (SO_ERROR is zero) or unsuc-
              cessfully  (SO_ERROR  is  one of the usual error
              codes listed here, explaining the reason for the
              failure).
修改如下:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
int fd, retval;
struct sockaddr_in addr;
struct timeval timeo = {3, 0};
socklen_t len = sizeof(timeo);
fd_set set;

fd = socket(AF_INET, SOCK_STREAM, 0);
if (argc == 4) timeo.tv_sec = atoi(argv[3]);
int savefl = fcntl(fd,F_GETFL);
fcntl(fd, F_SETFL, savefl | O_NONBLOCK);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
printf("%d\n", time(NULL));
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0)
{
close(fd);
printf("connected..1\n");
return 0;
}

if (errno != EINPROGRESS)
{
close(fd);
perror("connect..2");
return -1;
}
FD_ZERO(&set);
FD_SET(fd, &set);
retval = select(fd + 1, NULL, &set, NULL, &timeo);
if (retval == -1)
{
close(fd);
perror("select");
return -1;
}
else if(retval == 0)
{
close(fd);
fprintf(stderr, "timeout\n");
printf("%d\n", time(NULL));
return 0;
}

if(FD_ISSET (fd,&set))      //|| FD_ISSET(SockFd,&wset))
{
int error = 0;
socklen_t len = sizeof (error);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
{
printf ("getsockopt fail,connected fail\n");
return -1;
}

if (error == ETIMEDOUT)
{
printf ("connected timeout\n");
}

if(error == ECONNREFUSED)
{
printf("No one listening on the remote address.\n");
return -1;
}

if(error) return -1;
}
printf ("connected .. 3\n");
fcntl(fd, F_SETFL, savefl);
close (fd);

return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言网络编程中,如果你希望在连接建立过程中设置一个超时时间,可以使用非阻塞模式的套接字和select函数来实现。 首先,你需要将套接字设置为非阻塞模式。可以使用fcntl函数或设置套接字的O_NONBLOCK标志来实现。这样,在调用connect函数时,它将立即返回,而不会阻塞程序的执行。 接下来,你可以使用select函数来监视套接字的状态。通过在select函数的timeout参数中设置一个合适的超时时间(例如1秒),可以在一定时间内检查套接字的状态。如果在超时时间内,套接字变为可写状态(表示连接成功),则连接建立成功。否则,如果超时时间到达但套接字仍然不可写,表示连接失败。 以下是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int connect_with_timeout(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int timeout_sec) { // Set socket to non-blocking mode int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); // Start connect int ret = connect(sockfd, addr, addrlen); if (ret == 0) { // Connect immediately return 0; } else if (ret == -1 && errno != EINPROGRESS) { // Connect error return -1; } // Wait for connection or timeout fd_set writefds; FD_ZERO(&writefds); FD_SET(sockfd, &writefds); struct timeval timeout; timeout.tv_sec = timeout_sec; timeout.tv_usec = 0; ret = select(sockfd + 1, NULL, &writefds, NULL, &timeout); if (ret <= 0) { // Timeout or error return -1; } // Check if socket is writable int valopt; socklen_t len = sizeof(int); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &valopt, &len); if (valopt != 0) { // Connect error return -1; } // Connection successful return 0; } int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); exit(1); } struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); int ret = connect_with_timeout(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr), 1); if (ret == 0) { printf("Connection successful\n"); } else { printf("Connection failed\n"); } close(sockfd); return 0; } ``` 这个示例代码中,connect_with_timeout函数封装了设置非阻塞模式和使用select函数进行连接超时判断的过程。在主函数中,你可以根据需要指定服务器的IP地址和端口号,并设置适当的超时时间。如果连接成功,将打印"Connection successful",否则将打印"Connection failed"。 请注意,这只是一个简单的示例代码,实际使用时可能需要进行错误处理和适当的调整。另外,网络连接成功与失败还可能与网络环境、服务器状态等因素有关。因此,在实际应用中,你可能需要根据具体情况进行进一步的优化和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值