异步连接与断开epoll的(Linux的)(Async connect and disconnect

2019-06-23 16:40发布

我需要异步连接,并使用epoll的为Linux断开连接的TCP客户端。 有内线。 在Windows功能,如ConnectEx,DisconnectEx,的AcceptEx等..在TCP服务器标准接受功能正在工作,但在TCP客户端不工作的连接和断开......所有的套接字是非阻塞。

我怎样才能做到这一点?

谢谢!

Answer 1:

要做到无阻塞连接(),假设插座已经作出非阻塞:

int res = connect(fd, ...);
if (res < 0 && errno != EINPROGRESS) {
    // error, fail somehow, close socket
    return;
}

if (res == 0) {
    // connection has succeeded immediately
} else {
    // connection attempt is in progress
}

对于第二种情况,其中connect()的失败,EINPROGRESS(只有在这种情况下),你必须等待套接字是可写的,例如,对于epoll的规定,你等待EPOLLOUT此套接字上。 一旦你收到此通知,它是可写的(有epoll的, 希望得到一个EPOLLERR或EPOLLHUP事件),检查连接尝试的结果:

int result;
socklen_t result_len = sizeof(result);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) {
    // error, fail somehow, close socket
    return;
}

if (result != 0) {
    // connection failed; error code is in 'result'
    return;
}

// socket is ready for read()/write()

根据我的经验,在Linux上,连接()从来没有马上成功,你总是要等待可写性。 然而,例如,在FreeBSD,我已经看到了非阻塞connect()以本地主机后面的时候了。



Answer 2:

从以往的经验,当检测无阻塞连接,epoll的是选择和投票方式有点不同。

与epoll的:

connect()调用作出后,检查返回代码。

如果连接不能立即完成,然后注册epoll的EPOLLOUT事件。

调用epoll_wait()。

如果连接失败,您的活动将与EPOLLERR或EPOLLHUP填写,否则EPOLLOUT将被触发。



Answer 3:

我已经试过了索尼的解决方案和epoll_ctl将返回无效的参数。 所以我想也许这样做的正确方法是如下:

1.创建socketfd和epollfd

2.使用epoll_ctl到socketfd和epollfd与epoll的事件相关联。

3.do连接(socketfd,...)

4,检查返回值或错误号

5.如果错误号== EINPROGRESS,做epoll_wait



Answer 4:

我有一个“完整”的答案在这里以防别人正在寻找这样的:

#include <sys/epoll.h>
#include <errno.h>
....
....
int retVal = -1;
socklen_t retValLen = sizeof (retVal);

int status = connect(socketFD, ...);
if (status == 0)
 {
   // OK -- socket is ready for IO
 }
else if (errno == EINPROGRESS)
 {
    struct epoll_event newPeerConnectionEvent;
    int epollFD = -1;
    struct epoll_event processableEvents;
    unsigned int numEvents = -1;

    if ((epollFD = epoll_create (1)) == -1)
    {
       printf ("Could not create the epoll FD list. Aborting!");
       exit (2);
    }     

    newPeerConnectionEvent.data.fd = socketFD;
    newPeerConnectionEvent.events = EPOLLOUT | EPOLLIN | EPOLLERR;

    if (epoll_ctl (epollFD, EPOLL_CTL_ADD, socketFD, &newPeerConnectionEvent) == -1)
    {
       printf ("Could not add the socket FD to the epoll FD list. Aborting!");
       exit (2);
    }

    numEvents = epoll_wait (epollFD, &processableEvents, 1, -1);

    if (numEvents < 0)
    {
       printf ("Serious error in epoll setup: epoll_wait () returned < 0 status!");
       exit (2);
    }

    if (getsockopt (socketFD, SOL_SOCKET, SO_ERROR, &retVal, &retValLen) < 0)
    {
       // ERROR, fail somehow, close socket
    }

    if (retVal != 0) 
    {
       // ERROR: connect did not "go through"
    }   
}
else
{
   // ERROR: connect did not "go through" for other non-recoverable reasons.
   switch (errno)
   {
     ...
   }
}


文章来源: Async connect and disconnect with epoll (Linux)