异步连接和断开与 epoll (Linux)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10187347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Async connect and disconnect with epoll (Linux)
提问by Alexander
I need async connect and disconnect for tcp client using epoll for Linux. There are ext. functions in Windows, such as ConnectEx, DisconnectEx, AcceptEx, etc... In tcp server standard accept function is working, but in tcp client doesn't working connect and disconnect... All sockets are nonblocking.
我需要使用 epoll for Linux 为 tcp 客户端进行异步连接和断开连接。有分机。Windows 中的函数,例如 ConnectEx、DisconnectEx、AcceptEx 等...在 tcp 服务器标准接受功能正在工作,但在 tcp 客户端不工作连接和断开连接...所有套接字都是非阻塞的。
How can I do this?
我怎样才能做到这一点?
Thanks!
谢谢!
回答by Ambroz Bizjak
To do a non-blocking connect(), assuming the socket has already been made non-blocking:
要进行非阻塞 connect(),假设套接字已经成为非阻塞:
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
}
For the second case, where connect() failed with EINPROGRESS (and only in this case), you have to wait for the socket to be writable, e.g. for epoll specify that you're waiting for EPOLLOUT on this socket. Once you get notified that it's writable (with epoll, alsoexpect to get an EPOLLERR or EPOLLHUP event), check the result of the connection attempt:
对于第二种情况,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()
In my experience, on Linux, connect() never immediately succeeds and you always have to wait for writability. However, for example, on FreeBSD, I've seen non-blocking connect() to localhost succeeding right away.
根据我的经验,在 Linux 上,connect() 永远不会立即成功,您总是需要等待可写性。但是,例如,在 FreeBSD 上,我已经看到非阻塞 connect() 到 localhost 立即成功。
回答by Sonny
I have a "complete" answer here in case anyone else is looking for this:
如果其他人正在寻找这个,我在这里有一个“完整”的答案:
#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)
{
...
}
}
回答by Bugs
From experience, when detect non-blocking connection , epoll is a little different from select and poll.
根据经验,在检测非阻塞连接时,epoll 与 select 和 poll 有点不同。
with epoll:
与 epoll:
After connect() call is made, check return code.
调用 connect() 后,检查返回码。
If the connection can not be completed immediately, then register EPOLLOUT event with epoll.
如果连接不能立即完成,则向 epoll 注册 EPOLLOUT 事件。
Call epoll_wait().
调用 epoll_wait()。
if the connection failed, your events will be fill with EPOLLERR or EPOLLHUP, otherwise EPOLLOUT will be triggered.
如果连接失败,您的事件将填充 EPOLLERR 或 EPOLLHUP,否则将触发 EPOLLOUT。
回答by Aaron
I have tried the Sonny's solution and the epoll_ctl will return invalid argument. So i think maybe the right way to do this is as follow:
我已经尝试过 Sonny 的解决方案,并且 epoll_ctl 将返回无效参数。所以我认为也许正确的方法如下:
1.create socketfd and epollfd
1.创建socketfd和epollfd
2.use epoll_ctl to associate the socketfd and epollfd with epoll event.
2.使用epoll_ctl将socketfd和epollfd与epoll事件关联起来。
3.do connect(socketfd,...)
3.做连接(socketfd,...)
4.check the return value or errno
4.检查返回值或errno
5.if errno == EINPROGRESS, do epoll_wait
5.如果errno == EINPROGRESS,做epoll_wait