Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3928660
  • 博文数量: 93
  • 博客积分: 3189
  • 博客等级: 中校
  • 技术积分: 4229
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-02 13:29
个人简介

出没于杭州和青岛的程序猿一枚,对内核略懂一二

文章分类

全部博文(93)

文章存档

2016年(2)

2015年(3)

2014年(11)

2013年(29)

2012年(16)

2011年(5)

2010年(5)

2009年(22)

分类: LINUX

2014-02-08 11:30:42

关于tcp连接的异步connect实现流程如下:
(1)设置socket连接为NONBLOCK
(2)调用connect函数
(3)poll函数检测fd
(4)判断poll函数的返回值来确定连接是否建立

下面是一个测试代码。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <poll.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/ip.h>
  7. #include <netinet/tcp.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <strings.h>
  11. #include <string.h>
  12. int main(int argc, char **argv)
  13. {
  14.         int old;
  15.         int err;
  16.         int errlen = sizeof(err);
  17.         struct sockaddr_in addr;
  18.         socklen_t len = sizeof(struct sockaddr_in);
  19.         int timeo;
  20.         int fd;
  21.         struct pollfd pfd;
  22.         int ret;

  23.         if (argc != 4) {
  24.                 printf("Usage %s ip port timeout\n", argv[0]);
  25.                 return -1;
  26.         }
  27.         timeo = atoi(argv[3]);
  28.         fd = socket(AF_INET, SOCK_STREAM, 0);
  29.         if (fd < 0) {
  30.                 printf("Create socket error erno=%d : %s\n", errno,strerror(errno));
  31.                 return -1;
  32.         }

  33.         bzero(&addr, sizeof(addr));
  34.         addr.sin_family = AF_INET;
  35.         addr.sin_addr.s_addr = inet_addr(argv[1]);
  36.         addr.sin_port = htons(atoi(argv[2]));

  37.         old = fcntl(fd, F_GETFL, 0);
  38.         if (fcntl(fd, F_SETFL, old|O_NONBLOCK) < 0) {
  39.                 printf("setting fd error: errno,%s\n", errno,strerror(errno));
  40.                 close(fd);
  41.                  return -1;
  42.         }

  43.         if (connect(fd, (struct sockaddr*)&addr, len) == -1 &&
  44.                         errno != EINPROGRESS) {
  45.                 printf("Error in connect: %d,%s\n", errno,strerror(errno));
  46.                 close(fd);
  47.                 return -1;
  48.         }

  49.         pfd.fd = fd;
  50.         pfd.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
  51.         errno = 0;

  52.         if (timeo <= 0)
  53.                 timeo = -1;

  54.         ret = poll(&pfd, 1, timeo);

  55.         if (ret < 0) {
  56.                 if (errno == EINTR) {
  57.                         close(fd);
  58.                         return -1;
  59.                 }
  60.                 close(fd);
  61.                 return -1;

  62.         } else if (0 == ret) {
  63.                 close(fd);
  64.                 return -1;
  65.         }

  66.         if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  67.                 close(fd);
  68.                 return -1;
  69.         }
  70.         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, (socklen_t*)&errlen) == -1) {
  71.                 close(fd);
  72.                  return -1;
  73.         }
  74.         if (err != 0) {//check the SO_ERROR state
  75.                 errno = err;
  76.                 close(fd);
  77.                 return -1;
  78.         }

  79.         fcntl(fd, F_SETFL, old);
  80.         printf("Connect real OK\n");
  81.         return fd;
  82. }

在这个代码,如果传入的超时时间小于等于0,那么poll会一直等待。
但是要注意的是,这里所谓的一直等待,绝对不是无限期等下去,具体等待时间与系统配置参数有关。
比如你连接的目的地址不存在,那么syn最多重试发送net.ipv4.tcp_syn_retries次后就会返回POLLERR。
阅读(17370) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~