我需要使用epoll for Linux的tcp客户端的异步连接和断开连接。有分机。在Windows中的功能,如ConnectEx,DisconnectEx,AcceptEx等... 在tcp服务器标准接受函数正在工作,但在tcp客户端不工作连接和断开...所有套接字都是非阻塞的。异步连接和断开与epoll(Linux)
我该怎么做?
谢谢!
我需要使用epoll for Linux的tcp客户端的异步连接和断开连接。有分机。在Windows中的功能,如ConnectEx,DisconnectEx,AcceptEx等... 在tcp服务器标准接受函数正在工作,但在tcp客户端不工作连接和断开...所有套接字都是非阻塞的。异步连接和断开与epoll(Linux)
我该怎么做?
谢谢!
要做到无阻塞连接(),假设插座已经作出无阻塞:
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
}
对于第二种情况,其中连接()与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()到localhost是成功的。
我有一个“完整”的答案在这里以防别人正在寻找这样的:
#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)
{
...
}
}
我相信你的错误检查epoll_wait()是不正确的 - 你应该总是通过getsockopt检查连接尝试的结果( SO_ERROR),即使你没有得到EPOLLERR。在手册页http://linux.die.net/man/2/connect中看到EINPROGRESS另外,assert()是处理严重错误的错误方法 - 这意味着你已经*证明*它永远不会发生。使用exit(),即使定义了NDEBUG,也会终止程序。 – 2012-06-05 21:47:47
刚刚添加了建议的编辑。未编辑的版本似乎适用于我。 – Sonny 2012-06-06 01:20:11
从经验来看,检测无阻塞连接时,epoll的是选择和投票方式有点不同。
with epoll:
connect()调用完成后,检查返回码。
如果连接无法立即完成,请用epoll注册EPOLLOUT事件。
调用epoll_wait()。
如果连接失败,您的事件将被填充EPOLLERR或EPOLLHUP,否则EPOLLOUT将被触发。
是的,我在回答中忘记提及epoll可以返回EPOLLERR或EPOLLHUP以及EPOLLOUT。感谢提及,它已被纠正。 – 2013-10-08 12:08:36
我已经尝试了桑尼的解决方案,epoll_ctl将返回无效的参数。所以我想也许这样做是按照正确的方式:
1.创建socketfd和epollfd
2.使用epoll_ctl到socketfd和epollfd与epoll的事件相关联。
3.do连接(socketfd,...)
4.检查返回值或errno
5.如果错误号== EINPROGRESS,做epoll_wait
这可以帮助你: http://stackoverflow.com/questions/2875002/non-blocking-tcp-connect-with-epoll – 2012-04-17 08:11:47
作为链接DJB页面建议的可能替代方案,我想建议尝试“dup '和'关闭'描述符(并使用重复)。没有测试,但它应该工作,在我的理解。文档声明,不检查'close'的返回值是严重的编程错误,因为它可能会返回以前的错误。这正是你想要的(如果'close'给出错误,'connect'失败)。虽然当然如果你使用'epoll',那么你肯定会有一个操作系统,其中'getsockopt(SO_ERROR)'将会正常工作... – Damon 2012-04-17 09:08:03
如果可行,最简单的选择是等到connect()返回之后再设置NON_BLOCK。 – delicateLatticeworkFever 2012-04-17 13:11:10