我需要使用 epoll for Linux 为 tcp 客户端异步连接和断开连接。有分机。Windows 中的函数,例如 ConnectEx、DisconnectEx、AcceptEx 等...
我怎样才能做到这一点?
谢谢!
我需要使用 epoll for Linux 为 tcp 客户端异步连接和断开连接。有分机。Windows 中的函数,例如 ConnectEx、DisconnectEx、AcceptEx 等...
我怎样才能做到这一点?
谢谢!
做一个非阻塞的 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
}
对于第二种情况,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 上,connect() 永远不会立即成功,您总是必须等待可写性。但是,例如,在 FreeBSD 上,我已经看到非阻塞 connect() 到 localhost 立即成功。
从经验来看,在检测非阻塞连接时,epoll 与 select 和 poll 有点不同。
使用 epoll:
进行 connect() 调用后,检查返回码。
如果无法立即完成连接,则向 epoll 注册 EPOLLOUT 事件。
调用 epoll_wait()。
如果连接失败,您的事件将被 EPOLLERR 或 EPOLLHUP 填充,否则将触发 EPOLLOUT。
我在这里有一个“完整”的答案,以防其他人正在寻找这个:
#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)
{
...
}
}
我已经尝试过 Sonny 的解决方案,并且 epoll_ctl 将返回无效参数。所以我认为也许正确的方法如下:
1.创建socketfd和epollfd
2.使用epoll_ctl将socketfd和epollfd与epoll事件关联起来。
3.做连接(socketfd,...)
4.检查返回值或errno
5.如果errno == EINPROGRESS,做epoll_wait