首页 > 代码库 > 由select/epoll返回的非阻塞connect还会是EINPROGRESS状态吗?

由select/epoll返回的非阻塞connect还会是EINPROGRESS状态吗?

一般情况下,我们像下面代码中所示的这样使用非阻塞connect:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
 
#define EPOLL_MAXEVENTS 64
 
int main(int argc, char *argv[])
{
    int fd, epfd, flags, status, ret, nevents, i, slen;
    struct sockaddr_in addr;
    struct in_addr remote_ip;
    struct epoll_event ev, events[EPOLL_MAXEVENTS];;
 
 
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
        perror("socket failed");
        return -1;
    }
 
    status = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int))) {
        perror("setsockopt failed");
        return -1;
    }
 
   flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = 9999;
    if (inet_pton(AF_INET, "10.232.129.43", &addr.sin_addr) <= 0) {
        perror("inet_pton error");
        return -1;
    }
 
 
 
    ret = connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
    if (ret == 0) {
        printf("non-blocking connect success. connect complete immediately");
        close(fd);
        return -1;
    }
 
    if (ret < 0 && errno != EINPROGRESS) {
        perror("connect error!");
        return -1;
    }
 
 
    epfd = epoll_create(EPOLL_MAXEVENTS);
 ev.events = EPOLLOUT;
    ev.data.fd = fd;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1 ) {
        perror("epoll_ctl error");
        goto finish;
    }
    printf("add connect fd into epoll");
 
    memset(events, 0, sizeof(events));
 
    for (;;) {
 
        nevents = epoll_wait(epfd, events, EPOLL_MAXEVENTS, -1);
 
        if (nevents < 0) {
            perror("epoll_wait failed");
            goto finish;
        }
 
        for (i = 0; i < nevents; i++) {
 
            if (events[i].data.fd == fd) {
 
                if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen)
                    < 0)
                {
                    perror("getsockopt error!");
                    goto finish;
                }
                if (status != 0) {
                    perror("connect error!");
                    goto finish;
                }
 
                printf("non-blocking connect success!");
 
                if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) == -1 ) {
                    perror("epoll_ctl error");
                    return 0;
                }
 
                /* DO write... */
            }
        }
    }
 
 finish:
    close(fd);
    close(epfd);
 
    return 0;
}

  在上面的代码中需要注意几点:

1,什么时候connect返回成功?

   三次握手中的client如果收到server对SYN的ACK,connect就会返回。

2,非阻塞的connect成功返回后,用getsockopt获得的SO_ERROR码还会使EINPROGRESS吗?

   不会。除非是epoll设置的超时时间到达,否则epoll_wait返回fd后,表明fd已经可写,connect已经建立成功。此时如果getsockopt获取到的SO_ERROR 状态码是status表明connect已失败,不可能再是EINPROGRESS。